Files
pcp/src/pcp.c

597 lines
13 KiB
C
Raw Normal View History

2013-11-04 17:43:22 +01:00
/*
This file is part of Pretty Curved Privacy (pcp1).
Copyright (C) 2013 T.Linden.
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 <http://www.gnu.org/licenses/>.
You can contact me by mail: <tlinden AT cpan DOT org>.
*/
2013-10-28 22:50:05 +01:00
#include "pcp.h"
#include "defines.h"
void usage(int error) {
2013-10-28 22:50:05 +01:00
fprintf(stderr, PCP_HELP_INTRO);
if(error == 0)
fprintf(stderr, PCP_HELP);
2013-10-28 22:50:05 +01:00
version();
exit(EXIT_FAILURE);
}
2013-10-28 22:50:05 +01:00
void version() {
fprintf(stderr, "pcp version %d.%d.%d, use --help to learn how to use.\n",
2013-10-28 22:50:05 +01:00
PCP_VERSION_MAJOR, PCP_VERSION_MINOR, PCP_VERSION_PATCH);
exit(0);
}
char *default_vault() {
char *path = ucmalloc(1024);;
snprintf(path, 1024, "%s/.pcpvault", getenv("HOME"));
return path;
}
int main (int argc, char **argv) {
int opt, mode, usevault, useid, userec, lo, armor, detach, signcrypt, exportformat;
2013-10-28 22:50:05 +01:00
char *vaultfile = default_vault();
char *outfile = NULL;
char *infile = NULL;
char *sigfile = NULL;
2013-10-28 22:50:05 +01:00
char *keyid = NULL;
char *id = NULL;
char *xpass = NULL;
2014-02-07 11:55:44 +01:00
char *extra = NULL;
2014-01-20 16:07:01 +01:00
plist_t *recipient = NULL;
2013-10-28 22:50:05 +01:00
FILE *in;
PCP_EXIT = 0;
errno = 0;
debug = 0;
mode = 0;
usevault = 0;
useid = 0;
userec = 0;
2013-11-18 21:48:24 +01:00
lo = 0;
armor = 0;
detach = 0;
2014-01-27 16:12:43 +01:00
signcrypt = 0;
exportformat = EXP_FORMAT_NATIVE;
2013-10-28 22:50:05 +01:00
static struct option longopts[] = {
/* generics */
{ "vault", required_argument, NULL, 'V' },
{ "outfile", required_argument, NULL, 'O' },
{ "infile", required_argument, NULL, 'I' },
{ "keyid", required_argument, NULL, 'i' },
{ "text", required_argument, NULL, 't' },
{ "xpass", required_argument, NULL, 'x' },
{ "recipient", required_argument, NULL, 'r' },
2013-10-28 22:50:05 +01:00
/* key management */
{ "keygen", no_argument, NULL, 'k' },
{ "listkeys", no_argument, NULL, 'l' },
{ "export-secret", no_argument, NULL, 's' },
{ "export-public", no_argument, NULL, 'p' },
{ "import-secret", no_argument, NULL, 'S' },
{ "import-public", no_argument, NULL, 'P' },
{ "remove-key", no_argument, NULL, 'R' },
{ "edit-key", no_argument, NULL, 'E' },
{ "export-yaml", no_argument, NULL, 'y' },
{ "export-format", required_argument, NULL, 'F' },
2013-10-28 22:50:05 +01:00
/* crypto */
{ "encrypt", no_argument, NULL, 'e' },
{ "encrypt-me", no_argument, NULL, 'm' },
{ "decrypt", no_argument, NULL, 'd' },
2013-10-28 22:50:05 +01:00
/* encoding */
{ "z85-encode", no_argument, NULL, 'z' },
{ "z85-decode", no_argument, NULL, 'Z' },
2013-10-28 22:50:05 +01:00
/* globals */
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "debug", no_argument, NULL, 'D' },
/* signing */
{ "sign", no_argument, NULL, 'g' },
{ "check-signature", no_argument, NULL, 'c' },
{ "sigfile", required_argument, NULL, 'f' },
{ NULL, 0, NULL, 0 }
2013-10-28 22:50:05 +01:00
};
while ((opt = getopt_long(argc, argv, "klV:vdehsO:i:I:pSPRtEx:DzZr:gcymf:b1F:",
2013-10-28 22:50:05 +01:00
longopts, NULL)) != -1) {
2013-10-28 22:50:05 +01:00
switch (opt) {
case 0:
switch(lo) {
case 's':
printf("sign\n");
break;
}
break;
2013-10-28 22:50:05 +01:00
case 'k':
mode += PCP_MODE_KEYGEN;
usevault = 1;
break;
case 'l':
mode += PCP_MODE_LISTKEYS;
usevault = 1;
break;
case 's':
mode += PCP_MODE_EXPORT_SECRET;
usevault = 1;
break;
case 'p':
mode += PCP_MODE_EXPORT_PUBLIC;
usevault = 1;
break;
case 'P':
mode += PCP_MODE_IMPORT_PUBLIC;
usevault = 1;
break;
case 'S':
mode += PCP_MODE_IMPORT_SECRET;
usevault = 1;
break;
case 'R':
2013-10-28 22:50:05 +01:00
mode += PCP_MODE_DELETE_KEY;
usevault = 1;
break;
case 't':
mode += PCP_MODE_TEXT;
2013-11-18 21:48:24 +01:00
usevault = 0;
2013-10-28 22:50:05 +01:00
break;
case 'E':
mode += PCP_MODE_EDIT;
usevault = 1;
break;
case 'e':
mode += PCP_MODE_ENCRYPT;
usevault = 1;
break;
case 'm':
mode += PCP_MODE_ENCRYPT_ME;
break;
2013-10-28 22:50:05 +01:00
case 'd':
mode += PCP_MODE_DECRYPT;
usevault = 1;
break;
case 'z':
armor = 1;
2013-10-28 22:50:05 +01:00
break;
case 'Z':
2014-02-09 15:49:52 +01:00
armor = 2;
2013-10-28 22:50:05 +01:00
break;
case 'F':
if(strncmp(optarg, "pbp", 3) == 0) {
exportformat = EXP_FORMAT_PBP;
}
else if(strncmp(optarg, "pcp", 3) == 0) {
exportformat = EXP_FORMAT_NATIVE;
}
else if(strncmp(optarg, "yaml", 3) == 0) {
exportformat = EXP_FORMAT_YAML;
}
else if(strncmp(optarg, "c", 3) == 0) {
exportformat = EXP_FORMAT_C;
}
else if(strncmp(optarg, "py", 3) == 0) {
exportformat = EXP_FORMAT_PY;
}
else if(strncmp(optarg, "perl", 3) == 0) {
exportformat = EXP_FORMAT_PERL;
}
2014-02-13 20:20:50 +01:00
else if(strncmp(optarg, "c", 3) == 0) {
exportformat = EXP_FORMAT_C;
}
else {
warn("Unknown export format specified, using native\n");
exportformat = EXP_FORMAT_NATIVE;
}
break;
case 'g':
mode += PCP_MODE_SIGN;
usevault = 1;
break;
case 'c':
mode += PCP_MODE_VERIFY;
usevault = 1;
break;
case 'f':
sigfile = ucmalloc(strlen(optarg)+1);
strncpy(sigfile, optarg, strlen(optarg)+1);
detach = 1;
break;
case 'y':
mode += PCP_MODE_YAML;
usevault = 1;
break;
2013-10-28 22:50:05 +01:00
case 'V':
strncpy(vaultfile, optarg, 1024);
break;
case 'O':
outfile = ucmalloc(strlen(optarg)+1);
strncpy(outfile, optarg, strlen(optarg)+1);
break;
case 'I':
infile = ucmalloc(strlen(optarg)+1);
strncpy(infile, optarg, strlen(optarg)+1);
break;
case 'i':
keyid = ucmalloc(19);
strncpy(keyid, optarg, 19);
useid = 1;
break;
case 'x':
xpass = ucmalloc(strlen(optarg)+1);
strncpy(xpass, optarg, strlen(optarg)+1);
break;
case 'r':
2014-01-20 16:07:01 +01:00
p_add(&recipient, optarg);
userec = 1;
break;
2013-10-28 22:50:05 +01:00
case 'D':
debug = 1;
break;
case 'v':
version();
case 'h':
usage(0);
2013-10-28 22:50:05 +01:00
default:
usage(1);
2013-10-28 22:50:05 +01:00
}
}
argc -= optind;
argv += optind;
if(mode == 0) {
2014-02-09 15:49:52 +01:00
/* turn -z|-Z into a mode if there's nothing else specified */
if(armor == 1) {
mode = PCP_MODE_ZENCODE;
}
else if(armor == 2) {
mode = PCP_MODE_ZDECODE;
}
else {
version();
return 1;
}
}
2014-01-27 16:12:43 +01:00
if(mode == PCP_MODE_ENCRYPT + PCP_MODE_SIGN) {
mode = PCP_MODE_ENCRYPT;
signcrypt = 1;
}
if(mode == PCP_MODE_DECRYPT + PCP_MODE_VERIFY) {
mode = PCP_MODE_DECRYPT;
signcrypt = 1;
}
sodium_init(); /* FIXME: better called from the lib? */
errno = 0; /* FIXME: workaround for https://github.com/jedisct1/libsodium/issues/114 */
if(mode == PCP_MODE_ENCRYPT && useid == 0 && userec == 0) {
usevault = 0;
mode = PCP_MODE_ENCRYPT_ME;
}
2014-02-07 11:55:44 +01:00
if(argc >= 1) {
/* ok, there are arguments left on the commandline.
treat it as filename or recipient, depending on
current mode and other given parameters */
extra = ucmalloc(strlen(argv[0])+1);
strncpy(extra, argv[0], strlen(argv[0])+1);
switch (mode) {
case PCP_MODE_DECRYPT:
if(infile == NULL)
infile = extra;
break;
case PCP_MODE_ENCRYPT:
if(infile == NULL)
infile = extra;
else if(userec == 0 && useid == 0) {
userec = 1;
int i;
for (i=0; i<argc; i++) {
p_add(&recipient, argv[i]);
}
free(extra);
}
break;
case PCP_MODE_IMPORT_PUBLIC:
case PCP_MODE_IMPORT_SECRET:
if(infile == NULL)
infile = extra;
break;
case PCP_MODE_EXPORT_SECRET:
case PCP_MODE_EXPORT_PUBLIC:
if(outfile == NULL)
outfile = extra;
else if(useid == 0 && userec == 0) {
p_add(&recipient, extra);
userec = 1;
}
break;
case PCP_MODE_VERIFY:
if(infile == NULL)
infile = extra;
else if (useid == 0) {
id = extra;
useid = 1;
}
break;
case PCP_MODE_SIGN:
if(infile == NULL)
infile = extra;
else if(outfile == NULL && detach == 0)
outfile = extra;
break;
default:
free(extra); /* not used */
}
}
/* check if there's some enviroment we could use */
if(usevault == 1) {
char *_vaultfile = getenv("PCP_VAULT");
if(_vaultfile != NULL) {
strncpy(vaultfile, _vaultfile, strlen(_vaultfile)+1);
}
}
if(debug == 0) {
char *_debug = getenv("PCP_DEBUG");
if(_debug != NULL) {
debug = 1;
}
}
2013-10-28 22:50:05 +01:00
if(usevault == 1) {
pcphash_init();
2013-10-28 22:50:05 +01:00
vault = pcpvault_init(vaultfile);
if(vault != NULL) {
switch (mode) {
case PCP_MODE_KEYGEN:
pcp_keygen(xpass);
2013-10-28 22:50:05 +01:00
if(xpass != NULL)
free(xpass);
break;
case PCP_MODE_LISTKEYS:
pcp_listkeys();
break;
case PCP_MODE_EXPORT_SECRET:
if(useid) {
id = pcp_normalize_id(keyid);
if(id != NULL) {
pcp_exportsecret(id, useid, outfile, armor, xpass);
2013-10-28 22:50:05 +01:00
free(id);
}
}
else {
pcp_exportsecret(NULL, useid, outfile, armor, xpass);
2013-10-28 22:50:05 +01:00
}
break;
case PCP_MODE_EXPORT_PUBLIC:
if(useid) {
id = pcp_normalize_id(keyid);
if(id == NULL)
break;
2013-10-28 22:50:05 +01:00
}
pcp_exportpublic(id, xpass, outfile, exportformat, armor);
if(xpass != NULL)
free(xpass);
if(recipient != NULL)
free(recipient);
2013-10-28 22:50:05 +01:00
break;
case PCP_MODE_IMPORT_PUBLIC:
if(infile == NULL)
in = stdin;
else {
if((in = fopen(infile, "rb")) == NULL) {
fatal("Could not open input file %s\n", infile);
free(infile);
break;
}
}
pcp_importpublic(vault, in);
2013-10-28 22:50:05 +01:00
break;
case PCP_MODE_IMPORT_SECRET:
if(infile == NULL)
in = stdin;
else {
if((in = fopen(infile, "rb")) == NULL) {
fatal("Could not open input file %s\n", infile);
free(infile);
break;
}
}
pcp_importsecret(vault, in, xpass);
2013-10-28 22:50:05 +01:00
break;
case PCP_MODE_DELETE_KEY:
if(useid) {
id = pcp_normalize_id(keyid);
if(id != NULL) {
pcpdelete_key(id);
free(id);
}
}
else {
fatal("You need to specify a key id (--keyid)!\n");
}
break;
case PCP_MODE_EDIT:
if(useid) {
id = pcp_normalize_id(keyid);
if(id != NULL) {
pcpedit_key(id);
free(id);
}
}
else {
fatal("You need to specify a key id (--keyid)!\n");
}
break;
case PCP_MODE_ENCRYPT:
2014-01-20 16:07:01 +01:00
if(useid == 1 && userec == 0) {
/* one dst, FIXME: make id a list as well */
2013-10-28 22:50:05 +01:00
id = pcp_normalize_id(keyid);
2014-01-27 16:12:43 +01:00
pcpencrypt(id, infile, outfile, xpass, NULL, signcrypt);
}
2014-01-20 16:07:01 +01:00
else if(useid == 0 && userec == 1) {
/* multiple dst */
2014-01-27 16:12:43 +01:00
pcpencrypt(NULL, infile, outfile, xpass, recipient, signcrypt);
}
2013-10-28 22:50:05 +01:00
else {
/* -i and -r specified */
2014-01-20 16:07:01 +01:00
fatal("You can't specify both -i and -r, use either -i or -r!\n");
2013-10-28 22:50:05 +01:00
}
2014-01-20 16:07:01 +01:00
if(id != NULL)
free(id);
if(xpass != NULL)
free(xpass);
if(recipient != NULL)
p_clean(recipient);
2014-01-20 16:07:01 +01:00
2013-10-28 22:50:05 +01:00
break;
case PCP_MODE_DECRYPT:
if(useid) {
id = pcp_normalize_id(keyid);
if(id != NULL) {
2014-01-27 16:12:43 +01:00
pcpdecrypt(id, useid, infile, outfile, xpass, signcrypt);
2013-10-28 22:50:05 +01:00
free(id);
}
}
else {
2014-01-27 16:12:43 +01:00
pcpdecrypt(NULL, useid, infile, outfile, xpass, signcrypt);
2013-10-28 22:50:05 +01:00
}
if(xpass != NULL)
free(xpass);
break;
case PCP_MODE_SIGN:
if(detach) {
if(outfile != NULL && sigfile != NULL)
fatal("You can't both specify -O and -f, use -O for std signatures and -f for detached ones\n");
else
pcpsign(infile, sigfile, xpass, armor, detach);
}
else
pcpsign(infile, outfile, xpass, armor, detach);
break;
case PCP_MODE_VERIFY:
if(useid) {
id = pcp_normalize_id(keyid);
if(id != NULL) {
pcpverify(infile, sigfile, id, detach);
free(id);
}
}
else {
pcpverify(infile, sigfile, NULL, detach);
}
break;
case PCP_MODE_YAML:
pcpexport_yaml(outfile);
break;
2013-10-28 22:50:05 +01:00
default:
/* */
2013-10-28 22:50:05 +01:00
goto ELSEMODE;
break;
}
pcpvault_close(vault);
pcphash_clean();
free(vaultfile);
2013-10-28 22:50:05 +01:00
}
}
else {
ELSEMODE:
switch (mode) {
case PCP_MODE_ZENCODE:
pcpz85_encode(infile, outfile);
break;
case PCP_MODE_ZDECODE:
pcpz85_decode(infile, outfile);
break;
case PCP_MODE_ENCRYPT_ME:
2014-01-27 16:12:43 +01:00
pcpencrypt(NULL, infile, outfile, xpass, NULL, 0);
break;
case PCP_MODE_TEXT:
if(infile != NULL) {
pcptext_infile(infile);
}
else {
pcphash_init();
vault = pcpvault_init(vaultfile);
if(! useid && infile == NULL) {
pcptext_vault(vault);
2013-11-18 21:48:24 +01:00
}
else {
id = pcp_normalize_id(keyid);
if(id != NULL) {
pcptext_key(id);
free(id);
2013-11-18 21:48:24 +01:00
}
}
pcpvault_close(vault);
pcphash_clean();
free(vaultfile);
}
break;
2013-11-18 21:48:24 +01:00
2013-10-28 22:50:05 +01:00
default:
/* mode params mixed */
fatal("Sorry, invalid combination of commandline parameters (0x%04X)!\n", mode);
2013-10-28 22:50:05 +01:00
break;
}
}
fatals_ifany();
2014-02-13 20:20:50 +01:00
fatals_done();
2013-10-28 22:50:05 +01:00
return PCP_EXIT;
}