diff options
Diffstat (limited to 'nix/libstore/local-store.cc')
-rw-r--r-- | nix/libstore/local-store.cc | 87 |
1 files changed, 70 insertions, 17 deletions
diff --git a/nix/libstore/local-store.cc b/nix/libstore/local-store.cc index cbbd8e901d..8c479002ec 100644 --- a/nix/libstore/local-store.cc +++ b/nix/libstore/local-store.cc @@ -21,6 +21,7 @@ #include <stdio.h> #include <time.h> #include <grp.h> +#include <ctype.h> #if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H #include <sched.h> @@ -1231,39 +1232,91 @@ static void checkSecrecy(const Path & path) } -static std::string runAuthenticationProgram(const Strings & args) +/* Return the authentication agent, a "guix authenticate" process started + lazily. */ +static std::shared_ptr<Agent> authenticationAgent() { - Strings fullArgs = { "authenticate" }; - fullArgs.insert(fullArgs.end(), args.begin(), args.end()); // append - return runProgram(settings.guixProgram, false, fullArgs); + static std::shared_ptr<Agent> agent; + + if (!agent) { + Strings args = { "authenticate" }; + agent = std::make_shared<Agent>(settings.guixProgram, args); + } + + return agent; +} + +/* Read an integer and the byte that immediately follows it from FD. Return + the integer. */ +static int readInteger(int fd) +{ + string str; + + while (1) { + char ch; + ssize_t rd = read(fd, &ch, 1); + if (rd == -1) { + if (errno != EINTR) + throw SysError("reading an integer"); + } else if (rd == 0) + throw EndOfFile("unexpected EOF reading an integer"); + else { + if (isdigit(ch)) { + str += ch; + } else { + break; + } + } + } + + return stoi(str); +} + +/* Read from FD a reply coming from 'guix authenticate'. The reply has the + form "CODE LEN:STR". CODE is an integer, where zero indicates success. + LEN specifies the length in bytes of the string that immediately + follows. */ +static std::string readAuthenticateReply(int fd) +{ + int code = readInteger(fd); + int len = readInteger(fd); + + string str; + str.resize(len); + readFull(fd, (unsigned char *) &str[0], len); + + if (code == 0) + return str; + else + throw Error(str); } /* Sign HASH with the key stored in file SECRETKEY. Return the signature as a string, or raise an exception upon error. */ static std::string signHash(const string &secretKey, const Hash &hash) { - Strings args; - args.push_back("sign"); - args.push_back(secretKey); - args.push_back(printHash(hash)); + auto agent = authenticationAgent(); + auto hexHash = printHash(hash); - return runAuthenticationProgram(args); + writeLine(agent->toAgent.writeSide, + (format("sign %1%:%2% %3%:%4%") + % secretKey.size() % secretKey + % hexHash.size() % hexHash).str()); + + return readAuthenticateReply(agent->fromAgent.readSide); } /* Verify SIGNATURE and return the base16-encoded hash over which it was computed. */ static std::string verifySignature(const string &signature) { - Path tmpDir = createTempDir("", "guix", true, true, 0700); - AutoDelete delTmp(tmpDir); + auto agent = authenticationAgent(); - Path sigFile = tmpDir + "/sig"; - writeFile(sigFile, signature); + writeLine(agent->toAgent.writeSide, + (format("verify %1%:%2%") + % signature.size() % signature).str()); - Strings args; - args.push_back("verify"); - args.push_back(sigFile); - return runAuthenticationProgram(args); + return readAuthenticateReply(agent->fromAgent.readSide); } void LocalStore::exportPath(const Path & path, bool sign, |