/** * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Written by Raphaƫl Gertz */ //Required for mkostemp, O_CLOEXEC, strdup, memmem #define _GNU_SOURCE //Required for SSIZE_MAX, LONG_MAX #include //Required for pid_t, kill, waitpid #include #include //Required for printf, sscanf, sprintf #include //Required for struct stat, fstat #include //Required for closedir, DIR, opendir, readdir, struct dirent #include //Required for close, dup2, execve, fork, read, STDERR_FILENO, STDOUT_FILENO, STDIN_FILENO, write #include //Required for open, O_CLOEXEC, O_NOATIME, O_NOFOLLOW #include //Required for atoi, calloc, exit, EXIT_FAILURE, EXIT_SUCCESS, free, getenv, malloc, realloc #include //Required for memchr, memcpy, memmem, strdup, strlen, strncmp #include //Required for bool #include //Required for nanosleep #include //Default passphrase max size #define DEFAULT_PASSPHRASE_SIZE_MAX 512 //Default keyfile max size //XXX: file should be maximum 8192*1024-1 character long #define DEFAULT_KEYFILE_SIZE_MAX (8192 * 1024) //Default crypttab #define CRYPTTAB "/etc/crypttab" //Default cryptsetup #define CRYPTSETUP "/sbin/cryptsetup" //Systemd cryptsetup #define SYSTEMDCRYPTSETUP "/usr/lib/systemd/systemd-cryptsetup" //Default pid file #define IHTTPDPID "/run/ihttpd/ihttpd.pid" //Default systemd ask-password dir #define ASKPASSWORDDIR "/run/systemd/ask-password" //Define child log #define ASKPASSWORDLOG "/run/ihttpd/log/child.askpassword.log" #define IHTTPDLOG "/run/ihttpd/log/child.ihttpd.log" //Define form uri #define FORMID "" #define FORMURI "/" FORMID ".html" //Create struct for http error status struct httpStatusStruct { int value; char *description; }; //Declare http error status array const struct httpStatusStruct httpStatuses[] = { {200, "OK"}, {400, "Bad Request"}, {405, "Method Not Allowed"}, {411, "Length Required"}, {500, "Internal Server Error"}, {503, "Service Unavailable"} }; /** * Prototype */ void die(const int, const char*); void header(const int, const char*); void showForm(const char*, const int, const int); void showMaintenance(); int extractValue(char**, int*, char*, int); int extractLuksDevice(char**, char**); int extractIHttpdPid(pid_t *); int extractAskPasswordPid(pid_t *); /** * Die with error */ void die(const int code, const char *err) { //TODO: see if we add a nice text/html template ? //Send content as text header(code, "text/plain"); //Print error line if available if (err != NULL) printf("%s", err); //Flush all if (fflush(NULL) == -1) { perror("fflush"); } //Exit with failure code exit(EXIT_FAILURE); } /** * Send header */ void header(const int code, const char *ctype) { int k; switch(code) { case 400: k = 1; break; case 405: k = 2; break; case 411: k = 3; break; case 500: k = 4; break; case 503: k = 5; break; default: k = 0; } //Send http status printf("Status: %d %s\r\n", httpStatuses[k].value, httpStatuses[k].description); //Make sure no cache printf("Cache-Control: no-cache, no-store, must-revalidate\r\n"); printf("Pragma: no-cache\r\n"); printf("Expires: 0\r\n"); printf("X-Robots-Tag: noindex, nofollow, noarchive, nosnippet, noodp\r\n"); printf("Content-type: %s\r\n\r\n", ctype); } /** * Show form */ void showForm(const char *requestUri, const int keyfileSizeMax, const int passphraseSizeMax) { header(503, "text/html"); printf("\r\n"); printf("\r\n"); printf("\r\n"); printf("Key upload form!\r\n"); printf("\r\n"); printf("\r\n"); printf("\r\n"); printf("
\r\n"); printf("
Upload key
\r\n", requestUri, keyfileSizeMax); printf("
Type key
\r\n", requestUri, passphraseSizeMax); printf("
\r\n"); printf("\r\n"); printf("\r\n"); } /** * Show maintenance */ void showMaintenance() { header(503, "text/html"); printf("\r\n"); printf("\r\n"); printf("\r\n"); printf("Service unavailable!\r\n"); printf("\r\n"); printf("\r\n"); printf("\r\n"); printf("

Service unavailable!

\r\n"); printf("

The server is temporarily unable to service your\r\n"); printf("request due to maintenance downtime or capacity\r\n"); printf("problems. Please try again later.

\r\n"); printf("

Error 503

\r\n"); printf("
%s
%s
\r\n", getenv("SERVER_NAME"), getenv("SERVER_SOFTWARE")); printf("\r\n", FORMID); printf("\r\n"); printf("\r\n"); } /** * Extract value */ int extractValue(char **value, int *valueLength, char *contentType, int contentLength) { //Handle application/x-www-form-urlencoded request if (contentType != NULL && !strncmp(contentType, "application/x-www-form-urlencoded", 33)) { //Indexes and return int i, k, v, r; //Declare key and buf char *key, *buf; //Allocate key if ((key = malloc(4*sizeof(char))) == NULL) { //Unable to allocate key return -1; } //Allocate buf to maximum possible value size + 1 for trailing \0 if ((buf = calloc(1, (DEFAULT_PASSPHRASE_SIZE_MAX+1)*sizeof(char))) == NULL) { //Unable to allocate value free(key); return -2; } //Char buffer char d = '\0'; //Char delimiter //XXX: initialised as & for new key, becomes = when fetching value char delim = '&'; for (i = 0, k = 0, v = 0; i < contentLength; i++) { //Safeguard against a value greater than DEFAULT_PASSPHRASE_SIZE_MAX //XXX: this should never happen because we should be protected by contentLength already if (v == DEFAULT_PASSPHRASE_SIZE_MAX+1) { //Invalid value free(key); free(buf); return -3; } //Read one character from stdin r = read(STDIN_FILENO, &d, 1); //Handle errors if (r < 0) { //Error while parsing post data free(key); free(buf); return -4; } else if (r == 0) { //Partial receive free(key); free(buf); return -5; } //Handle case where key has an other name if (i == 3) { //Check key is "key" and we get '=' as new char and assign delim to = if (strncmp(key, "key", 3) || (delim = d) != '=') { //Invalid key free(key); free(buf); return -6; } //Handle key or value separator in query string } else if (d == '&' || d == '=') { //Invalid query string free(key); free(buf); return -7; //Handle a value } else { //Save key char if (delim == '&') { key[k] = d; k++; //Save buf char } else { buf[v] = d; v++; } } } //Free key free(key); //Unescape and reduce value if not empty if (v > 0) { //Declare iterators int l,m, s = v; //Loop on value and reduce length on the fly for(l=0,m=0; m < v; l++,m++) { //Replace + with space if (buf[m] == '+') { buf[l] = ' '; //Skip partial present %XX } else if ( //Assign char (buf[l] = buf[m]) == '%' && //Check we didn't reach valueStrLength (m+2 < v) && //Check next two digits are valid ((buf[m+1] >= 'A' && buf[m+1] <= 'F') || (buf[m+1] >= 'a' && buf[m+1] <= 'f') || (buf[m+1] >= '0' && buf[m+1] <= '9')) && ((buf[m+2] >= 'A' && buf[m+2] <= 'F') || (buf[m+2] >= 'a' && buf[m+2] <= 'f') || (buf[m+2] >= '0' && buf[m+2] <= '9')) ) { 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'); m += 2; s -= 2; } } //Set value length *valueLength = s; //Alloc value if ((*value = malloc((*valueLength)*sizeof(char))) == NULL) { //Unable to alloc value free(key); free(buf); return -8; } //Copy value memcpy(*value, buf, *valueLength); } //Free buf free(buf); //Handle multipart/form-data request } else if (contentType != NULL && !strncmp(contentType, "multipart/form-data", 19)) { //Indexes and return int b, s, r; //Boundary length int boundaryLength = strlen(contentType) - 30 + 1; //Client send LF ending without CR int lfstyle = 0; //Declare boundary char *boundary; //Allocate boundary if ((boundary = calloc(1, boundaryLength*sizeof(char))) == NULL) { //Unable to allocate boundary return -9; } //Extract boundary memcpy(boundary, contentType + 30, boundaryLength - 1); //Declare buffers char *start, *buf; //Allocate buffer if ((buf = malloc(contentLength*sizeof(char))) == NULL) { //Unable to allocate buffer free(boundary); return -10; } //Char buffer char d = '\0'; //Loop for (b = 0, s = 0; b < contentLength; b++) { //Detect possible boundary //XXX: b is boundaryLength-1 + 2 after s //XXX: d will be a CR(CRLF line ending) or LF(LF line ending) or -(of final --) if (b == s + 2 + boundaryLength - 1 && !strncmp(boundary, buf + b - boundaryLength + 1, boundaryLength - 1)) { //Only after first boundary match if (s > 0) { //Trim line jump if (start[0] == '\r' && start[1] == '\n') { start += 2; lfstyle = 1; } else if (start[0] == '\n') { start++; } //Found flag bool found = false; //Allocate pointers char *new = start, *prev = start, *name = NULL; //Search for a new line while ((new = memchr(new, '\n', b - (new - buf)))) { //Jump to first character after new line new++; //Init line length int lineLength = new - prev - 1; //Remove chariage return if necessary if (prev[lineLength] == '\r') { lineLength--; lfstyle = 1; } //Break loop after headers end if (lineLength == 1) { break; } //Allocate a name buf of maximum line length //XXX: need to be filled with zero as we don't know what will comes with sscanf call and we rely on strlen if ((name = calloc(1, lineLength*sizeof(char))) == NULL) { //Unable to allocate name free(boundary); free(buf); return -11; } //Search for name if (sscanf(prev, "Content-Disposition: form-data; name=\"%[^\"]\"", name)) { //Realloc name if ((name = realloc(name, (strlen(name)+1)*sizeof(char))) == NULL) { //Unable to reduce name free(boundary); free(buf); free(name); return -12; } if (!strncmp(name, "key", 3)) { found = true; } } //Free name free(name); //Jump to next one prev = new; } //Init value if found if (found) { //Declare end char *end = buf + b - boundaryLength - 3; //Remove CR at end if provided //XXX: only remove CR at end if we encountered one before if (lfstyle) { end++; } //On too big keyfile if (end - new - 1 >= DEFAULT_KEYFILE_SIZE_MAX) { //Keyfile too large free(boundary); free(buf); return -13; } //On non empty value if (end - new > 1) { //Set value length *valueLength = end - new - 1; //Allocate value if ((*value = malloc((*valueLength)*sizeof(char))) == NULL) { //Unable to allocate value free(boundary); free(buf); return -14; } //Copy value memcpy(*value, new, *valueLength); } } } //Set start to matched boundary start = buf + b; } //Read one character from stdin r = read(STDIN_FILENO, &d, 1); //Handle errors if (r < 0) { //Error while parsing post data free(boundary); free(buf); return -15; } else if (r == 0) { //Partial receive free(boundary); free(buf); return -16; } //New line case if (d == '\n') { //Store new possible boundary start s = b + 1; } buf[b] = d; } //Free buffers free(boundary); free(buf); //Unhandled request } else { return -17; } //Send value return 0; } /** * Extract luks and device */ int extractLuksDevice(char **luks, char **device) { //Declare file descriptor int fd, bufLength; //Declare buf, device and luks pointer char *buf, *d, *l; //Declare stat struct struct stat *stats; //Open file if ((fd = open(CRYPTTAB, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) { //Can't open crypttab file return -1; } //Allocate stats if ((stats = calloc(1, sizeof(struct stat))) == NULL) { //Unable to allocate stats return -2; } //Stat file if (fstat(fd, stats) == -1) { //Can't stat crypttab return -3; } //Check file size if ((bufLength = stats->st_size) > SSIZE_MAX) { //Crypttab too big return -4; } //Allocate buf if ((buf = malloc(bufLength*sizeof(char))) == NULL) { //Unable to allocate buf return -5; } //Read file if ((read(fd, buf, bufLength)) < bufLength) { //Fail to read crypttab file return -6; } //Close file close(fd); //Free stats buffer free(stats); //Search first separator (\s|\t) after luks if ((l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, ' ', bufLength)) == NULL) { return -7; } //Jump to next char l++; //Search first separator (\s|\t) after device if ((d = memchr(l, ' ', bufLength - (l - buf))) == NULL && (d = memchr(l, ' ', bufLength - (l - buf))) == NULL && (d = memchr(l, '\n', bufLength - (l - buf))) == NULL) { return -8; } //Jump to next char d++; //Alloc luks if ((*luks = malloc((l - buf - 1)*sizeof(char))) == NULL) { return -9; } //Allocate device if ((*device = malloc((d - l - 1)*sizeof(char))) == NULL) { //Free and reset luks free(luks); luks=NULL; return -10; } //Copy luks memcpy(*luks, buf, l - buf - 1); //Terminate luks (*luks)[l - buf - 1] = '\0'; //Copy device memcpy(*device, l, d - l - 1); //Terminate device (*device)[d - l - 1] = '\0'; //Free buffer free(buf); //Success return 0; } /** * Extract ask-password pid */ int extractAskPasswordPid(pid_t *pid) { //Declare stuct dirent struct dirent *entry; //Declare askdir DIR *askdir; //Declare found int found = 0; //Allocate dirent struct if ((entry = calloc(1, sizeof(struct dirent))) == NULL) { //Unable to allocate entry return -1; } //Open systemd ask-password dir if ((askdir = opendir(ASKPASSWORDDIR)) == NULL) { //Can't open ask dir return -2; } //Change dir if (chdir(ASKPASSWORDDIR) == -1) { //Can't change to ask dir return -3; } //Loop on dir content while((entry = readdir(askdir))) { //Handle each ask.XXXXXX file if (!strncmp(entry->d_name, "ask.", 4) && strlen(entry->d_name) == 10) { //Declare file descriptor int fd, bufLength; //Declare buf char *buf; //Declare stat struct struct stat *stats; //Open file if ((fd = open(entry->d_name, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) { //Can't open ask file return -4; } //Allocate stats if ((stats = calloc(1, sizeof(struct stat))) == NULL) { //Unable to allocate stats return -5; } //Stat file if (fstat(fd, stats) == -1) { //Can't stat ask file return -6; } //Check file size if ((bufLength = stats->st_size) > SSIZE_MAX) { //Ask file too big return -7; } //Allocate buf if ((buf = malloc(bufLength*sizeof(char))) == NULL) { //Unable to allocate buf return -8; } //Read file if ((read(fd, buf, bufLength)) < bufLength) { //Fail to read ask file return -9; } //Close file close(fd); //Free stats buffer free(stats); //Allocate pointers char *nl = buf, *pl = buf, *e; //Allocate pid *pid = 0; //Search for a new line while ((nl = memmem(nl, bufLength - (nl - buf), "\n", strlen("\n")))) { //Jump to next char nl++; //Check if we have a = in line but not empty value ("=\n") if ((e = memmem(pl, bufLength - (pl - buf), "=", strlen("="))) && e < nl - 2) { //Jump to next char e++; //Look for PID if (!strncmp(pl, "PID", 3)) { //Declade pid string char *pidStr; //Allocate pid string if ((pidStr = malloc((nl - e)*sizeof(char))) == NULL) { //Unable to allocate pid string return -10; } //Copy pid memcpy(pidStr, e, nl - e - 1); //Terminate pid string pidStr[nl - e] = '\0'; //Check pid value if ((*pid = atoi(pidStr)) <= 1) { //Invalid pid return -11; } //Free pid string free(pidStr); //Found a valid process found++; } } //Jump prev line to new line pl = nl; } //Free buffers free(buf); } } //Close systemd ask-password dir if (closedir(askdir) == -1) { //Can't close ask dir return -13; } //Free entry free(entry); //Found no valid pid if (found == 0) { //No pid found return -14; //Found more than one pid } else if (found > 1) { //No pid found return -15; } //Success return 0; } /** * Extract ihttpd pid */ int extractIHttpdPid(pid_t *pid) { //Declare file descriptor int fd, bufLength; //Declare buf, device and luks pointer char *buf, *l, *pidStr; //Declare stat struct struct stat *stats; //Open file if ((fd = open(IHTTPDPID, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) { //Can't open crypttab file return -1; } //Allocate stats if ((stats = calloc(1, sizeof(struct stat))) == NULL) { //Unable to allocate stats return -2; } //Stat file if (fstat(fd, stats) == -1) { //Can't stat crypttab return -3; } //Check file size if ((bufLength = stats->st_size) > SSIZE_MAX) { //Crypttab too big return -4; } //Allocate buf if ((buf = malloc(bufLength*sizeof(char))) == NULL) { //Unable to allocate buf return -5; } //Read file if ((read(fd, buf, bufLength)) < bufLength) { //Fail to read crypttab file return -6; } //Close file close(fd); //Free stats buffer free(stats); //Search first separator (\s|\t|\n) after pid if ((l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, '\n', bufLength)) == NULL) { return -7; } //Jump to next char l++; //Alloc pid string if ((pidStr = malloc((l - buf - 1)*sizeof(char))) == NULL) { return -9; } //Copy luks memcpy(pidStr, buf, l - buf - 1); //Terminate luks pidStr[l - buf - 1] = '\0'; //Free buffer free(buf); //Store pid if ((*pid = atoi(pidStr)) <= 1) { //Invalid pid return -10; } //Free pid string free(pidStr); //Success return 0; } /** * Main function */ int main(int argc, char **argv) { //Get request method char *requestMethod = getenv("REQUEST_METHOD"); //Get request uri char *requestUri = getenv("REQUEST_URI"); //Handle unknown requests if (requestMethod == NULL || (strncmp(requestMethod, "GET", 3) && strncmp(requestMethod, "HEAD", 4) && strncmp(requestMethod, "POST", 4))) { //Send method not allowed die(405, "Unsupported request method"); //Handle get and head } else if (!strncmp(requestMethod, "GET", 3) || !strncmp(requestMethod, "HEAD", 4)) { //Check if we have form uri if (requestUri != NULL && strlen(requestUri) == strlen(FORMURI) && !strncmp(requestUri, FORMURI, strlen(FORMURI))) { //Send form showForm(requestUri, DEFAULT_KEYFILE_SIZE_MAX, DEFAULT_PASSPHRASE_SIZE_MAX); //Not form uri requested } else { //Send maintenance page showMaintenance(); } //Handle post } else /*if (!strncmp(requestMethod, "POST", 4))*/ { //Return value int ret; //Child pid pid_t pid; //Value length //XXX: will contain number of char in value without trailing \0 int valueLength; //Value string //XXX: will contain value without a tailing \0 char *value = NULL; //Content length int contentLength; //Content length string from env char *contentLengthStr = getenv("CONTENT_LENGTH"); //Content type char *contentType = getenv("CONTENT_TYPE"); //Declare luks and device char *luks = NULL, *device = NULL; //Declare cargv char **cargv = NULL; //Pairs of pipe for stdin, stdout and stderr int inPipe[2], errPipe[2]; //Handle unknown content type if (contentType == NULL || (strncmp(contentType, "application/x-www-form-urlencoded", 33) && strncmp(contentType, "multipart/form-data", 19))) { die(400, "Unknown content type"); } //Handle invalid multipart/form-data content type //XXX: max boundary length is 70 as per rfc1521 & rfc2046 if (!strncmp(contentType, "multipart/form-data", 19) && (strncmp(contentType, "multipart/form-data; boundary=", 30) || strlen(contentType) <= 30 || strlen(contentType) > 100)) { die(400, "Malformed boundary in multipart/form-data request"); } //Handle invalid content length //XXX: deny empty contentLength as chrome send a contentLength even for a device if (contentLengthStr == NULL || (contentLength = atoi(contentLengthStr)) <= 0) { die(411, "Invalid content length"); } //Handle application/x-www-form-urlencoded request length //XXX: limit to key=xyz where xyz can be all encoded in %XX if (!strncmp(contentType, "application/x-www-form-urlencoded", 33) && contentLength > (DEFAULT_PASSPHRASE_SIZE_MAX * 3 + 4)) { die(400, "Invalid application/x-www-form-urlencoded request length"); } //Handle multipart/form-data request length //XXX: limit to arbitrary 3 times the keyfile max size if (!strncmp(contentType, "multipart/form-data", 19) && contentLength > (DEFAULT_KEYFILE_SIZE_MAX * 3)) { die(400, "Invalid multipart/form-data request length"); } //Extract value if ((ret = extractValue(&value, &valueLength, contentType, contentLength)) < 0) { die(500, "Failed to extract value"); } //Extract luks and device if ((ret = extractLuksDevice(&luks, &device)) < 0) { die(500, "Failed to extract luks and device"); } //Declare cargv array char *cargvs[] = { CRYPTSETUP, "-d", "-", "luksOpen", device, luks, NULL }; //TODO: device cannot be an UUID=xyz, a resolved block device is required for it //char *scargvs[] = { SYSTEMDCRYPTSETUP, "attach", luks, device, "-", NULL }; //Check cryptsetup binary if (access(CRYPTSETUP, F_OK|X_OK) == -1) { //Check systemdcryptsetup binary if (access(SYSTEMDCRYPTSETUP, F_OK|X_OK) == -1) { die(500, "No cryptsetup available"); } else { //Set contextual env //TODO: resolve UUID in real device name //TODO: passing password through the socket is not possible, as it rely on password ending with \0 die(500, "systemd-cryptsetupd is not implementable"); } } else { //Set contextual env cargv = cargvs; } //Create stdin pipe if (pipe(inPipe) == -1) { die(500, "Failed to create in pipe"); } //Create stderr pipe if (pipe(errPipe) == -1) { die(500, "Failed to create err pipe"); } //Fork process if ((pid = fork()) == -1) { die(500, "Failed to fork"); } //Child process if (pid == 0) { //Child arge char *carge[] = { NULL }; //Free value free(value); //Redirect stdin to pipe if (dup2(inPipe[0], STDIN_FILENO) == -1) { die(500, "Failed to redirect in pipe"); } //Close inPipe close(inPipe[0]); close(inPipe[1]); //Redirect stderr to pipe if (dup2(errPipe[1], STDERR_FILENO) == -1) { die(500, "Failed to redirect err pipe"); } //Close errPipe close(errPipe[0]); close(errPipe[1]); //Call cryptsetup if (execve(cargv[0], cargv, carge) == -1) { die(500, "Failed to call cryptsetup"); } //Parent process } else { //Free luks free(luks); //Free device free(device); //Close unused inPipe end close(inPipe[0]); //Close unused errPipe end close(errPipe[1]); //Send password on stdin anyway //XXX: this fail if device is already unlocked for example write(inPipe[1], value, valueLength); //Free value free(value); //Close stdin with EOF close(inPipe[1]); //Wait child if (waitpid(pid, &ret, 0) == -1) { die(500, "Failed to wait child"); } //Handle already in use device if (ret == 5) { die(500, "Device already in use"); //Handle already unlocked device //} else if (ret == 1280) { // die(200, "Device already unlocked"); //Handle invalid luks device //} else if (ret == 256) { // die(500, "Device is now a valid device"); //Handle no key available with this passphrase } else if (ret == 512) { die(500, "No slot for this value"); //Handle unexisting device or permission denied } else if (ret == 1014) { die(500, "Device doesn't exist or access denied"); //Unknown error } else if (ret != 0) { //Err length and counter int errLength = 2048, e = 0; //Declare err buffer char *err; //Buffer char char c; //Alloc err buffer if ((err = malloc(errLength*sizeof(char))) == NULL) { die(500, "Couldn't alloc err buffer"); } //Advance after ret code e = sprintf(err, "%d:", ret); //Fetch stderr and store in err buffer while(read(errPipe[0], &c, 1) > 0) { //Grow buffer if we reach end if (e == errLength) { if ((err = realloc(err, (errLength+2048)*sizeof(char))) == NULL) { die(500, "Couldn't grow err buffer"); } errLength += 2048; } //Store character err[e] = c; //Pass to next e++; } //Terminate err buffer err[e] = '\0'; //Realloc err buffer if ((err = realloc(err, (e+1)*sizeof(char))) == NULL) { die(500, "Couldn't ungrow err buffer"); } //Die with luks error die(500, err); } //Close errPipe close(errPipe[0]); } //Removed as it was making fail the process of booting sometimes #if 0 //Fork process if ((pid = fork()) == -1) { die(500, "Failed to fork"); } //IHttpd killing child process if (pid == 0) { //File descriptor int fd; //Declare ihttpd pid pid_t ihttpdPid; //Close stdin close(STDIN_FILENO); //Disable line buffering on stdout and stderr setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); //Redirect output to log if ((fd = open(IHTTPDLOG, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) == -1) { fprintf(stderr, "Open ihttpd child log failed\n"); } else { //Close stdout close(STDOUT_FILENO); //Redirect stdout on childlog if (dup2(fd, STDOUT_FILENO) == -1) { fprintf(stderr, "Redirect stdout to ihttpd child log failed\n"); } //Close stderr close(STDERR_FILENO); //Redirect stderr on childlog if (dup2(fd, STDERR_FILENO) == -1) { fprintf(stderr, "Redirect stderr to ihttpd child log failed\n"); } //Close childlog fd close(fd); } //Extract ihttpd pid if (extractIHttpdPid(&ihttpdPid) < 0) { fprintf(stderr, "Failed to extract ihttpd pid"); exit(EXIT_FAILURE); } //Close stdout and stderr without childlog if (fd == -1) { close(STDOUT_FILENO); close(STDERR_FILENO); } //Wait until get rattached to init(getppid()==1) //XXX: we are really blind here while(getppid() != 1) { //Sleep half a second if (usleep(500000) == -1 && fd != -1) { printf("Usleep failed\n"); } } //Termiate ihttpd if (kill(ihttpdPid, 0) == 0 && kill(ihttpdPid, SIGTERM) == -1 && fd != -1) { printf("Termiate ihttpd failed\n"); } //Sleep half a second if (usleep(500000) == -1 && fd != -1) { printf("Usleep failed\n"); } //Kill ihttpd if (kill(ihttpdPid, 0) == 0 && kill(ihttpdPid, SIGKILL) == -1) { printf("Kill ihttpd failed\n"); } //Parent process } else { #endif //Sleep before killing askpassword process if (usleep(500000) == -1) { die(500, "Usleep failed"); } //Fork process if ((pid = fork()) == -1) { die(500, "Failed to fork"); } //Ask password killing child process //XXX: we are blind here if (pid == 0) { //File descriptor int fd; //Declare ask password pid pid_t askPasswordPid; //Close stdin close(STDIN_FILENO); //Disable line buffering on stdout and stderr setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); //Redirect output to log if ((fd = open(ASKPASSWORDLOG, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) == -1) { fprintf(stderr, "Open ask password child log failed\n"); } else { //Close stdout close(STDOUT_FILENO); //Redirect stdout on childlog if (dup2(fd, STDOUT_FILENO) == -1) { fprintf(stderr, "Redirect stdout to ask password child log failed\n"); } //Close stderr close(STDERR_FILENO); //Redirect stderr on childlog if (dup2(fd, STDERR_FILENO) == -1) { fprintf(stderr, "Redirect stderr to ask password child log failed\n"); } //Close childlog fd close(fd); } //Extract ask password pid if (extractAskPasswordPid(&askPasswordPid) < 0) { fprintf(stderr, "Failed to extract ask password pid"); exit(EXIT_FAILURE); } //Close stdout and stderr without childlog if (fd == -1) { close(STDOUT_FILENO); close(STDERR_FILENO); } //Wait until get rattached to init(getppid()==1) //XXX: we are really blind here while(getppid() != 1) { //Sleep half a second if (usleep(500000) == -1 && fd != -1) { printf("Usleep failed\n"); } } //Termitate ask password if (kill(askPasswordPid, 0) == 0 && kill(askPasswordPid, SIGTERM) == -1 && fd != -1) { printf("Termiate ask password failed\n"); } //Sleep half a second if (usleep(500000) == -1 && fd != -1) { printf("Usleep failed\n"); } //Kill ask password if (kill(askPasswordPid, 0) == 0 && kill(askPasswordPid, SIGKILL) == -1) { printf("Kill ask password failed\n"); } //Parent process } else { //Process success header(200, "text/plain"); printf("Sent value, boot should resume now"); fflush(NULL); } #if 0 } #endif } exit(EXIT_SUCCESS); }