From: Walter Alejandro Iglesias Subject: mail(1) add any header from command line (diff adapted from Debian) To: tech@openbsd.org Date: Thu, 29 Aug 2024 16:39:36 +0200 In another thread I mentioned that debian bsd-mailx package is a patched version of OpenBSD mail(1) and that a useful feature present in that version is the option to add any header from the command line (option '-a' in this case). The diff below is an adaptation I made from this: https://github.com/deepin-community/bsd-mailx/blob/master/debian/patches/04-Add-custom-header.patch Where I: - Corrected a function declaration - Changed use strcpy() and strcat() for strndup() and strlcat(). - Added checks in puthead() to avoid duplicated headers. - Modified man page entry. After applying this patch you can: $ mail -a "Header: string" -a "AnotherHeader: string" ... I'm not truly convinced of how reliable could be adding this. I'd like the experts opinion. And if there could be any security implications. Index: def.h =================================================================== RCS file: /cvs/src/usr.bin/mail/def.h,v diff -u -p -r1.17 def.h --- def.h 28 Jan 2022 06:18:41 -0000 1.17 +++ def.h 29 Aug 2024 14:15:07 -0000 @@ -173,6 +173,7 @@ struct header { struct name *h_to; /* Dynamic "To:" string */ char *h_from; /* User-specified "From:" string */ char *h_subject; /* Subject string */ + char *h_header; /* Additional header string */ struct name *h_cc; /* Carbon copies string */ struct name *h_bcc; /* Blind carbon copies */ struct name *h_smopts; /* Sendmail options */ Index: extern.h =================================================================== RCS file: /cvs/src/usr.bin/mail/extern.h,v diff -u -p -r1.30 extern.h --- extern.h 21 May 2024 05:00:48 -0000 1.30 +++ extern.h 29 Aug 2024 14:15:07 -0000 @@ -162,7 +162,7 @@ void load(char *); struct var * lookup(char *); int mail(struct name *, struct name *, struct name *, struct name *, - char *, char *); + char *, char *, char *); void mail1(struct header *, int); void makemessage(FILE *, int); void mark(int); Index: mail.1 =================================================================== RCS file: /cvs/src/usr.bin/mail/mail.1,v diff -u -p -r1.83 mail.1 --- mail.1 31 Mar 2022 17:27:25 -0000 1.83 +++ mail.1 29 Aug 2024 14:15:07 -0000 @@ -63,6 +63,12 @@ with lines replaced by messages. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl a +Specify additional header fields on the command line such as "X-Loop: +foo@bar" etc. +You have to use quotes if the string contains spaces. +This argument may be specified more than once, the headers will then +be concatenated. .It Fl b Ar list Send blind carbon copies to .Ar list . @@ -1254,7 +1260,7 @@ and are not supported by this implementa .Nm mailx . .Pp The flags -.Op Fl bcdEIrv +.Op Fl abcdEIrv are extensions to the specification. .Sh HISTORY A Index: main.c =================================================================== RCS file: /cvs/src/usr.bin/mail/main.c,v diff -u -p -r1.35 main.c --- main.c 26 Jan 2021 18:21:47 -0000 1.35 +++ main.c 29 Aug 2024 14:15:07 -0000 @@ -103,6 +103,8 @@ main(int argc, char **argv) struct name *to, *cc, *bcc, *smopts; char *fromaddr; char *subject; + char *header = NULL; + size_t hlen = 0; char *ef; char nosrc = 0; char *rc; @@ -136,7 +138,7 @@ main(int argc, char **argv) smopts = NULL; fromaddr = NULL; subject = NULL; - while ((i = getopt(argc, argv, "EINb:c:dfinr:s:u:v")) != -1) { + while ((i = getopt(argc, argv, "EINa:b:c:dfeinr:s:u:v")) != -1) { switch (i) { case 'u': /* @@ -171,6 +173,32 @@ main(int argc, char **argv) */ subject = optarg; break; + + case 'a': + /* + * Give additional header fields for sending from + * non terminal + */ + if (header == NULL) { + header = strndup(optarg, strlen(optarg) + 1); + if (header == NULL) + err(1, NULL); + } else { + header = realloc(header, strlen(optarg) + + strlen(header) + 2); + if (header == NULL) + err(1, NULL); + hlen = strlcat(header, "\n", + strlen(header) + 2); + if (hlen >= strlen(header) + 2) + errx(1, "main: header too long"); + hlen = strlcat(header, optarg, + strlen(optarg) + strlen(header) + 1); + if (hlen >= strlen(optarg) + + strlen(header) + 1) + errx(1, "main: header too long"); + } + break; case 'f': /* * User is specifying file to "edit" with Mail, @@ -216,6 +244,7 @@ main(int argc, char **argv) */ bcc = cat(bcc, nalloc(optarg, GBCC)); break; + case 'e': case 'E': /* * Don't send messages with an empty body. @@ -269,7 +298,7 @@ main(int argc, char **argv) rc = "~/.mailrc"; load(expand(rc)); if (!rcvmode) { - mail(to, cc, bcc, smopts, fromaddr, subject); + mail(to, cc, bcc, smopts, fromaddr, subject, header); /* * why wait? */ Index: send.c =================================================================== RCS file: /cvs/src/usr.bin/mail/send.c,v diff -u -p -r1.26 send.c --- send.c 8 Mar 2023 04:43:11 -0000 1.26 +++ send.c 29 Aug 2024 14:15:07 -0000 @@ -279,13 +279,14 @@ statusput(struct message *mp, FILE *obuf */ int mail(struct name *to, struct name *cc, struct name *bcc, struct name *smopts, - char *fromaddr, char *subject) + char *fromaddr, char *subject, char *header) { struct header head; head.h_to = to; head.h_from = fromaddr; head.h_subject = subject; + head.h_header = header; head.h_cc = cc; head.h_bcc = bcc; head.h_smopts = smopts; @@ -306,6 +307,7 @@ sendmail(void *v) head.h_to = extract(str, GTO); head.h_from = NULL; head.h_subject = NULL; + head.h_header = NULL; head.h_cc = NULL; head.h_bcc = NULL; head.h_smopts = NULL; @@ -519,16 +521,22 @@ puthead(struct header *hp, FILE *fo, int gotcha = 0; from = hp->h_from ? hp->h_from : value("from"); - if (from != NULL) + if (from != NULL && strstr(hp->h_header, "From:") == NULL) fprintf(fo, "From: %s\n", from), gotcha++; - if (hp->h_to != NULL && w & GTO) + if (hp->h_to != NULL && w & GTO && strstr(hp->h_header, + "To:") == NULL) fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; - if (hp->h_subject != NULL && w & GSUBJECT) + if (hp->h_subject != NULL && w & GSUBJECT && strstr(hp->h_header, + "Subject:") == NULL) fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; - if (hp->h_cc != NULL && w & GCC) + if (hp->h_cc != NULL && w & GCC && strstr(hp->h_header, + "Cc:") == NULL) fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; - if (hp->h_bcc != NULL && w & GBCC) + if (hp->h_bcc != NULL && w & GBCC && strstr(hp->h_header, + "Bcc:") == NULL) fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; + if (hp->h_header != NULL && w) + fprintf(fo, "%s\n", hp->h_header), gotcha++; if (gotcha && w & GNL) (void)putc('\n', fo); return(0); -- Walter