summaryrefslogtreecommitdiff
path: root/sqmail-4.3.07/src/qmail-dksign.c
diff options
context:
space:
mode:
Diffstat (limited to 'sqmail-4.3.07/src/qmail-dksign.c')
-rwxr-xr-xsqmail-4.3.07/src/qmail-dksign.c512
1 files changed, 0 insertions, 512 deletions
diff --git a/sqmail-4.3.07/src/qmail-dksign.c b/sqmail-4.3.07/src/qmail-dksign.c
deleted file mode 100755
index 406afc1..0000000
--- a/sqmail-4.3.07/src/qmail-dksign.c
+++ /dev/null
@@ -1,512 +0,0 @@
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include "sig.h"
-#include "stralloc.h"
-#include "buffer.h"
-#include "error.h"
-#include "auto_qmail.h"
-#include "control.h"
-#include "str.h"
-#include "exit.h"
-#include "case.h"
-#include "constmap.h"
-#include "uint_t.h"
-#include "fd.h"
-#include "logmsg.h"
-#include "open.h"
-#include "fmt.h"
-#include "fmtqfn.h"
-#include "readwrite.h"
-#include "qmail.h"
-#include "wait.h"
-#include "pathexec.h"
-#include "rcpthosts.h"
-
-#define WHO "qmail-dksign"
-
-#define DOMAINKEYS "ssl/domainkeys/"
-
-/** @file qmail-dksign.c -- generate signature and attach in DKIM header to outgoing message
-
- Steps:
- ------
- a) DKIM controls: get private key for sending domain
- b) Prepare two staging files at queue/dkim (before and after signing)
- c) Read input at fd0 and insert CR for every line and store at dkim/x/pre
- d) DKIM sign the message with provided private key and store at dkim/y/post
- e) Copy signed file from fd to 0
- f) Invoke qmail-remote (respecting the \r\n)
- g) Remove staging files (pre/post)
-
- Hack for hybrid signatures:
- ---------------------------
-
- a) selector is a link to RSA private key
- b) selector2 is a link to Ed25519 private key
- c) Both are provided in the 'selector' field of dkimdomains separated by colon
- d) The coupled selector information is provided to qmail-dkim as: -yselector ,-Yselector2
- e) The RSA privat key is given unaltered
- f) The Ed25519 private is supplied as additional argument
- */
-
-char inbuf[BUFSIZE_LINE];
-buffer bi = BUFFER_INIT(read,0,inbuf,sizeof(inbuf));
-char outbuf[BUFSIZE_MESS];
-buffer bo = BUFFER_INIT(write,1,outbuf,sizeof(outbuf));
-
-void die(int e) { _exit(e); }
-void die_write(char *fn) { unlink(fn); die(53); };
-void die_read() { die(54); };
-void out(char *s) { if (buffer_puts(&bo,s) == -1) _exit(111); }
-void zero() { if (buffer_put(&bo,"\0",1) == -1) _exit(111); }
-void zerodie() { zero(); buffer_flush(&bo); _exit(111); }
-
-stralloc fndkin = {0};
-stralloc fndkout = {0};
-
-stralloc sender = {0}; // will be re-written
-stralloc senddomain = {0};
-stralloc originator = {0};
-stralloc dkimdomains = {0};
-struct constmap mapdkimdomains;
-
-stralloc ecckey = {0};
-stralloc rsakey = {0};
-char *dkimparams = 0;
-
-void temp_nomem()
-{
- out("ZOut of memory. (#4.3.0)\n");
- zerodie();
-}
-void temp_chdir()
-{
- out("ZUnable to switch to target directory. (#4.3.0)\n");
- zerodie();
-}
-void temp_create()
-{
- out("ZUnable to create DKIM stage file: ");
- out(error_str(errno));
- out(fndkin.s); out(". (#4.3.0)\n");
- zerodie();
-}
-void temp_unlink()
-{
- out("ZUnable to unlink DKIM stage file. (#4.3.0)\n");
- zerodie();
-}
-void temp_control()
-{
- out("ZUnable to read DKIM control files. (#4.3.0)\n");
- zerodie();
-}
-void perm_usage()
-{
- out("Zqmail-dksign was invoked improperly. (#5.3.5)\n");
- zerodie();
-}
-void temp_read()
-{
- out("DUnable to read message for DKIM signing. (#4.3.0)\n");
- zerodie();
-}
-void temp_nosignkey()
-{
- out("DCan't read sign key: ");
- out(rsakey.s);
- out(" or ");
- out(ecckey.s);
- out(". (#4.3.0)\n");
- zerodie();
-}
-
-int get_controls()
-{
- int i;
- stralloc domname = {0};
-
- if (control_init() == -1) temp_control();
-
- switch (control_readfile(&dkimdomains,"control/dkimdomains",0)) {
- case -1: return 0;
- case 0: if (!constmap_init(&mapdkimdomains,"",0,1)) temp_nomem(); break;
- case 1: if (!constmap_init(&mapdkimdomains,dkimdomains.s,dkimdomains.len,1)) temp_nomem(); break;
- }
-
-/* Check for disabled DKIM send domains */
-
- if (!stralloc_copys(&domname,"!")) temp_nomem();
- if (!stralloc_cats(&domname,senddomain.s)) temp_nomem();
- if (constmap(&mapdkimdomains,domname.s,domname.len)) return 0;
-
-/* Parenting domains; senddomain 0-terminated; lowercase */
-
- for (i = 0; i <= senddomain.len; ++i) {
- if ((i == 0) || (senddomain.s[i] == '.'))
- if ((dkimparams = constmap(&mapdkimdomains,senddomain.s + i,senddomain.len - i - 1))) {
- if (!stralloc_copys(&sender,senddomain.s + i)) temp_nomem();
- if (!stralloc_0(&sender)) temp_nomem();
- return 3;
- }
- }
-
-/* We sign only senddomains we take responsibility for: rcpthosts */
-
- if ((dkimparams = constmap(&mapdkimdomains,"=",1))) {
- if (rcpthosts_init() == -1) temp_control();
- if (rcpthosts(originator.s,originator.len)) {
- if ((control_readline(&sender,"control/defaultdomain") != 1))
- if (control_readline(&sender,"control/me") == -1) temp_control();
- if (!stralloc_0(&sender)) temp_nomem();
- return 2;
- }
- }
-
-/* Default settings for MTA: 'defaultdomain' or even 'me' */
-
- if ((dkimparams = constmap(&mapdkimdomains,"*",1))) {
- if ((control_readline(&sender,"control/defaultdomain") != 1))
- if (control_readline(&sender,"control/me") == -1) temp_control();
- if (!stralloc_0(&sender)) temp_nomem();
- return 1;
- }
-
- return 0;
-}
-
-void fnmake_dkim(unsigned long id)
-{
- fndkin.len = fmtqfn(fndkin.s,"queue/dkim/",id,1);
- id += id;
- fndkout.len = fmtqfn(fndkout.s,"queue/dkim/",id,1);
-}
-
-void dkim_unlink()
-{
- if (unlink(fndkin.s) == -1)
- if (errno != ENOENT) temp_unlink();
- if (unlink(fndkout.s) == -1)
- if (errno != ENOENT) temp_unlink();
-}
-
-void dkim_stage()
-{
- int r;
- int fd;
- int in, out;
- struct stat st;
- unsigned char tmpbuf[BUFSIZE_MESS + 2]; // intermediate write buffer
-
- if (!stralloc_ready(&fndkin,FMTQFN)) temp_nomem();
- if (!stralloc_ready(&fndkout,FMTQFN)) temp_nomem();
-
- fnmake_dkim(getpid()); // pre-staging
- dkim_unlink(); // duplicate, left over file
- fd = open_excl(fndkin.s);
- if (fd == -1) die_write(fndkin.s);
-
- buffer_init(&bi,read,0,inbuf,sizeof(inbuf));
- buffer_init(&bo,write,fd,outbuf,sizeof(outbuf));
-
- while((r = buffer_get(&bi,inbuf,sizeof(inbuf)))) { // read into buffer
- if (r == -1) temp_read();
-
- for (in = out = 0; in < r; in++) {
- if (inbuf[in] == '\r') continue; // ignore CR
- if (inbuf[in] != '\n') {
- tmpbuf[out++] = inbuf[in];
- } else { // add CR for every LF
- tmpbuf[out++] = '\r';
- tmpbuf[out++] = '\n';
- }
- }
- if (out) buffer_put(&bo,tmpbuf,out); // ok
- }
-
- if (buffer_flush(&bo) == -1) die(51);
- if (fstat(fd,&st) == -1) die_read();
- if (fsync(fd) == -1) die_write(fndkin.s);
- if (close(fd) == -1) die_write(fndkin.s);
-}
-
-/* to construct DKIM information */
-
-stralloc selector = {0};
-stralloc selectore = {0};
-stralloc sdid = {0};
-stralloc auid = {0};
-stralloc expire = {0};
-stralloc canon = {0}; // -c r = relax, s = simple, t = relaxed/simple, u = simple/realxed
-stralloc hash = {0}; // -z 1/2/3/4/5 sha1/sha2/both/ed25519/ed25519+rsa-sha256
-stralloc length = {0}; // -l
-
-/**
-
- qmail-dkim [-h|-v|-s] [tags] <msgfile> [<RSAkeyfile> <outfile> <Ed25519keyfile>]
- --------------------------------------------------------------------------------
- tags:
- ----
- -c<canonicalization> - r=relaxed [DEFAULT], s=simple, t=relaxed/simple, u=simple/relaxed
- -d<sdid> - Signing Domain Identifier,if not provided it will be determined from the envelope originator/from header
- -i<auid> - Agent User Identifier, usually the sender's email address (optional)
- -l - include body length tag (optional)
- -q - include query method tag
- -t - include a timestamp tag (optional)
- -x<expire_time> - the expire time in seconds since epoch (optional, DEFAULT = current time + 604800)
- -y<selector> - set RSA selector (DEFAULT: default)
- -Y<selector> - set Ed25519 selector (DEFAULT: default)
- -z<hash> - set signature type (1=sha1, 2=sha256, 3=both, 4=ed25519, 5=hybrid)
-*/
-
-int dkim_sign(const char *rsakeyfile,const char *ecckeyfile,const char *fnin,const char *fnout)
-{
- int child;
- int wstat;
- char *(args[17]);
- int i = 0;
-
- args[i] = "qmail-dkim"; ++i;
- args[i] = "-s"; ++i;
- args[i] = "-q"; ++i;
- if (sdid.len > 3) { args[i] = sdid.s; ++i; }
- if (selector.len > 3) { args[i] = selector.s; ++i; }
- if (selectore.len > 3) { args[i] = selectore.s; ++i; }
- if (auid.len > 3) { args[i] = auid.s; ++i; }
- if (expire.len > 3) { args[i] = expire.s; ++i; }
- if (canon.len > 2) { args[i] = canon.s; ++i; }
- if (hash.len > 2) { args[i] = hash.s; ++i; }
- if (length.len > 2) { args[i] = length.s; ++i; }
- args[i] = fnin; ++i;
- args[i] = rsakeyfile; ++i;
- args[i] = fnout; ++i;
- if (str_len(ecckeyfile) > 3) { args[i] = ecckeyfile; ++i; }
- args[i] = 0;
-
- if (!(child = vfork())) {
- pathexec(args);
- if (errno) _exit(111);
- _exit(100);
- }
-
- wait_pid(&wstat,child);
- if (wait_crashed(wstat)) return 1;
-
- switch (wait_exitcode(wstat)) {
- case 1: return 1;
- default: return 0;
- }
-}
-
-int qmail_remote(char **qargs,int fd)
-{
- int child;
- int wstat;
- char *(args[5]);
-
- args[0] = "qmail-remote";
- args[1] = qargs[1];
- args[2] = qargs[2];
- args[3] = qargs[3];
- args[4] = 0;
-
- if (!(child = vfork())) {
- if (fd) {
- if (fd_move(0,fd) == -1) _exit(111);
- if (fd_copy(2,1) == -1) _exit(111);
- }
- pathexec(args);
- if (errno) _exit(111);
- _exit(100);
- }
-
- wait_pid(&wstat,child);
- if (wait_crashed(wstat)) return 1;
-
- switch (wait_exitcode(wstat)) {
- case 111: return 1;
- default: return 0;
- }
-}
-
-void dkim_setup()
-{
- int c, i, j, k, l;
- char *opt, *pos;
-
- /* defaults: selector=default, IETF format, q=dns/txt, z=2, c=r */
-
- if (!stralloc_copys(&sdid,"-d")) temp_nomem();
- if (!stralloc_cat(&sdid,&sender)) temp_nomem();
- if (!stralloc_0(&sdid)) temp_nomem();
- if (!stralloc_copys(&selector,"-ydefault")) temp_nomem();
- if (!stralloc_0(&selector)) temp_nomem();
- if (!stralloc_copys(&selectore,"-Yeddy")) temp_nomem();
- if (!stralloc_0(&selectore)) temp_nomem();
- if (!stralloc_copys(&canon,"-cr")) temp_nomem();
- if (!stralloc_0(&canon)) temp_nomem();
- if (!stralloc_copys(&hash,"-z2")) temp_nomem();
- if (!stralloc_0(&hash)) temp_nomem();
-
- /* domain:selector,selectore|sdid|[auid|~]|expire|c:z:l; c=[r|s|t|u], z=[1,2,3,4,5], l=l */
-
- if (dkimparams && *dkimparams) {
- i = str_chr(dkimparams,'|');
- pos = dkimparams + i;
- if (*pos == '|' || *pos == '\0') { // selector
- dkimparams[i] = '\0';
- c = str_chr(dkimparams,','); // selectore=eddy
- if (dkimparams[c] == ',') {
- dkimparams[c] = '\0';
- if (str_len(dkimparams + c + 1)) {
- if (!stralloc_copys(&selectore,"-Y")) temp_nomem();
- if (!stralloc_cats(&selectore,dkimparams + c + 1)) temp_nomem();
- if (!stralloc_0(&selectore)) temp_nomem();
- }
- } else if (str_len(dkimparams)) { // selector=default
- if (!stralloc_copys(&selector,"-y")) temp_nomem();
- if (!stralloc_cats(&selector,dkimparams)) temp_nomem();
- if (!stralloc_0(&selector)) temp_nomem();
- }
-
- j = str_chr(dkimparams + i + 1,'|');
- pos = dkimparams + i + j + 1;
- if (*pos == '|' || *pos == '\0') { // sdid; domain in DKIM header
- dkimparams[i + j + 1] = '\0';
- if (!stralloc_copys(&sdid,"-d")) temp_nomem();
- if (!stralloc_cats(&sdid,dkimparams + i + 1)) temp_nomem();
- if (!stralloc_0(&sdid)) temp_nomem();
-
- k = str_chr(dkimparams + i + j + 2,'|');
- pos = dkimparams + i + j + k + 2;
- if (*pos == '|' || *pos == '\0') { // auid = identifier
- dkimparams[i + j + k + 2] = '\0';
- if (!stralloc_copys(&auid,"-i")) temp_nomem();
- if (dkimparams[i + j + 2] == '~') {
- if (!stralloc_cat(&auid,&originator)) temp_nomem();
- } else
- if (!stralloc_cats(&auid,dkimparams + i + j + 2)) temp_nomem();
-
- if (!stralloc_0(&auid)) temp_nomem();
-
- l = str_chr(dkimparams + i + j + k + 3,'|');
- pos = dkimparams + i + j + k + l + 3;
- if (*pos == '|' || *pos == '\0') { // expire after n secs
- dkimparams[i + j + k + l + 3] = '\0';
- if (!stralloc_copys(&expire,"-x")) temp_nomem();
- if (!stralloc_cats(&expire,dkimparams + i + j + k + 3)) temp_nomem();
- if (!stralloc_0(&expire)) temp_nomem();
-
- /* Options to follow */
-
- opt = dkimparams + i + j + k + l + 4;
- if (*opt == '\0') return;
- if (*opt != ':') {
- if (!stralloc_copys(&canon,"-c")) temp_nomem(); // canonicalization
- if (!stralloc_catb(&canon,opt,1)) temp_nomem();
- if (!stralloc_0(&canon)) temp_nomem();
- ++opt; if (*opt == '\0') return; // next colon
- }
- if (*opt != ':' || *opt == '\0') return;
- if (*opt == ':') ++opt;
- if (*opt != ':') {
- if (!stralloc_copys(&hash,"-z")) temp_nomem(); // hash
- if (!stralloc_catb(&hash,opt,1)) temp_nomem();
- if (!stralloc_0(&hash)) temp_nomem();
- ++opt; if (*opt == '\0') return; // next colon
- }
- if (*opt != ':' || *opt == '\0') return;
- if (*opt == ':') ++opt;
- if (*opt != ':' && *opt == 'l') {
- if (!stralloc_copys(&length,"-l")) temp_nomem(); // length
- if (!stralloc_0(&length)) temp_nomem();
- }
- }
- }
- }
- }
- }
-
- return;
-}
-
-int main(int argc,char **args)
-{
- int i;
- int fdin = 0; // initial read from FD 0
- int nkey = 0;
- char *(qargs[4]);
- struct stat st;
-
- qargs[0] = args[0];
- qargs[1] = args[1]; // host
- qargs[2] = args[2]; // originator
- qargs[3] = args[3]; // recipient
-
- umask(033);
- sig_pipeignore();
- if (argc < 4) perm_usage();
- if (chdir(auto_qmail) == -1) temp_chdir();
-
- if (str_len(args[2]) > 2) {
- i = str_chr(args[2],'@');
- if (*(args[2] + i) == '@')
- if (!stralloc_copys(&senddomain,args[2] + i + 1)) temp_nomem();
- }
- if (!stralloc_0(&senddomain)) temp_nomem();
- if (!stralloc_copys(&originator,args[2])) temp_nomem();
-
- if (!get_controls()) {
- qmail_remote(qargs,fdin);
- _exit(0);
- }
-
- dkim_setup(); // sender is evaluated from originator (senddomain)
-
- /* Setup keys: they are composed from selector */
-
- case_lowerb(sender.s,sender.len); // needs to be lowercase
- if (!stralloc_copys(&rsakey,DOMAINKEYS)) temp_nomem();
- if (!stralloc_cats(&rsakey,sender.s)) temp_nomem();
- if (!stralloc_cats(&rsakey,"/")) temp_nomem();
-
- if (!stralloc_copys(&ecckey,DOMAINKEYS)) temp_nomem();
- if (!stralloc_cats(&ecckey,sender.s)) temp_nomem();
- if (!stralloc_cats(&ecckey,"/")) temp_nomem();
-
- /* RSA key common for SHA1 and SHA256: rsakeyfile -> selector */
-
- if (!stralloc_cats(&rsakey,selector.s + 2)) temp_nomem(); // -y prepended
- if (!stralloc_0(&rsakey)) temp_nomem();
- if (stat(rsakey.s,&st) != -1)
- if (open_read(rsakey.s) > 0) ++nkey;
-
- /* ECC key follows: ecckeyfile -> (,)selector2 */
-
- if (!stralloc_cats(&ecckey,selectore.s + 2)) temp_nomem(); // -Y prepended
- if (!stralloc_0(&ecckey)) temp_nomem();
- if (stat(ecckey.s,&st) != -1)
- if (open_read(ecckey.s) > 0) ++nkey;
-
- /* We got keys - go for staging */
-
- if (nkey) { // otherwise no key exists; why bother
- dkim_stage();
- if (!dkim_sign(rsakey.s,ecckey.s,fndkin.s,fndkout.s)) {
- fdin = open_read(fndkout.s);
- if (fdin == -1) die_read();
- } else {
- fdin = fndkin.s; // DKIM key failed to sign
- }
- } else
- temp_nosignkey();
-
- qmail_remote(qargs,fdin); // closes fdin
- if (nkey) dkim_unlink();
-
- _exit(0);
-}