--- contrib/dma/dma.h.orig 2025-04-30 09:57:01.366753000 +0300 +++ contrib/dma/dma.h 2025-05-07 02:23:51.061070000 +0300 @@ -125,6 +125,7 @@ struct queue { FILE *mailf; char *tmpf; const char *sender; + const char *fullname; }; struct config { --- contrib/dma/dma.c.orig 2025-04-30 09:57:01.366671000 +0300 +++ contrib/dma/dma.c 2025-05-07 02:35:58.163100000 +0300 @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -95,12 +96,74 @@ sighup_handler(int signo) (void)signo; /* so that gcc doesn't complain */ } +static char Latin1ToASCII[128] = +{ + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, + 99, 80, 36, 89, 124, 36, 34, 99, 97, 60, 45, 45, 114, 45, 111, 42, + 50, 51, 39, 117, 80, 46, 44, 49, 111, 62, 42, 42, 42, 63, 65, 65, + 65, 65, 65, 65, 65, 67, 69, 69, 69, 69, 73, 73, 73, 73, 68, 78, 79, + 79, 79, 79, 79, 88, 79, 85, 85, 85, 85, 89, 80, 66, 97, 97, 97, 97, + 97, 97, 97, 99, 101, 101, 101, 101, 105, 105, 105, 105, 100, 110, + 111, 111, 111, 111, 111, 47, 111, 117, 117, 117, 117, 121, 112, 121 +}; + +/* + * Use pw_gecos out of struct passwd obtained with getpwnam() + * for specified user to form full user name. + */ +static const char * +fullname(const char *user) +{ + struct passwd *pw; + char *end, *p, *s; + size_t len, rest; + static char buf[256]; /* compatible with sendmail */ + + if (NULL == (pw = getpwnam(user))) + return (NULL); + s = pw->pw_gecos; + if (*s == '*') + s++; + end = buf + sizeof(buf); + p = buf; + + while (*s && p < end) + switch(*s) { + case ',': case ';': case '%': + if (s == pw->pw_gecos) /* empty name part in a GECOS */ + return (NULL); + *p = '\0'; /* success */ + return (buf); + case '&': /* insert the name */ + rest = end - p; + len = strlcpy(p, user, rest); + if (len >= rest) /* buffer overflow */ + return (NULL); + *p = toupper(*p); + p += len; + s++; + break; + default: + if ((unsigned char) *s >= 128) + *p++ = Latin1ToASCII[(unsigned char) *s++ - 128]; + else + *p++ = *s++; + } + + if (s == pw->pw_gecos || *s || p == end) /* empty GECOS or buffer overflow */ + return (NULL); + *++p = '\0'; /* success */ + return (buf); +} + static char * set_from(struct queue *queue, const char *osender) { const char *addr; char *sender; + queue->fullname = NULL; if (config.masquerade_user) { addr = config.masquerade_user; } else if (osender) { @@ -109,6 +172,7 @@ set_from(struct queue *queue, const char *osender) addr = getenv("EMAIL"); } else { addr = username; + queue->fullname = fullname(username); } if (!strchr(addr, '@')) { --- contrib/dma/mail.c.orig 2025-05-07 02:33:24.521058000 +0300 +++ contrib/dma/mail.c 2025-05-07 02:30:06.326336000 +0300 @@ -495,7 +495,11 @@ readmail(struct queue *queue, int nodot, int recp_from (uintmax_t)random(), hostname()); } else if (!had_from) { - had_from = 1; + had_from = 1; + if (queue->fullname) + snprintf(newline, sizeof(newline), + "From: %s <%s>\n", queue->fullname, queue->sender); + else snprintf(newline, sizeof(newline), "From: <%s>\n", queue->sender); } if (fwrite(newline, strlen(newline), 1, queue->mailf) != 1)