aboutsummaryrefslogtreecommitdiffstats
path: root/to.c
diff options
context:
space:
mode:
Diffstat (limited to 'to.c')
-rw-r--r--to.c827
1 files changed, 0 insertions, 827 deletions
diff --git a/to.c b/to.c
deleted file mode 100644
index 052a2354..00000000
--- a/to.c
+++ /dev/null
@@ -1,827 +0,0 @@
-/* $OpenBSD: to.c,v 1.44 2019/11/12 20:21:46 gilles Exp $ */
-
-/*
- * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
- * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
- * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <event.h>
-#include <fcntl.h>
-#include <imsg.h>
-#include <limits.h>
-#include <inttypes.h>
-#include <netdb.h>
-#include <pwd.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "smtpd.h"
-#include "log.h"
-
-static const char *in6addr_to_text(const struct in6_addr *);
-static int alias_is_filter(struct expandnode *, const char *, size_t);
-static int alias_is_username(struct expandnode *, const char *, size_t);
-static int alias_is_address(struct expandnode *, const char *, size_t);
-static int alias_is_filename(struct expandnode *, const char *, size_t);
-static int alias_is_include(struct expandnode *, const char *, size_t);
-static int alias_is_error(struct expandnode *, const char *, size_t);
-
-const char *
-sockaddr_to_text(struct sockaddr *sa)
-{
- static char buf[NI_MAXHOST];
-
- if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0,
- NI_NUMERICHOST))
- return ("(unknown)");
- else
- return (buf);
-}
-
-static const char *
-in6addr_to_text(const struct in6_addr *addr)
-{
- struct sockaddr_in6 sa_in6;
- uint16_t tmp16;
-
- memset(&sa_in6, 0, sizeof(sa_in6));
- sa_in6.sin6_len = sizeof(sa_in6);
- sa_in6.sin6_family = AF_INET6;
- memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
-
- /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
- if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
- IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
- memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
- sa_in6.sin6_scope_id = ntohs(tmp16);
- sa_in6.sin6_addr.s6_addr[2] = 0;
- sa_in6.sin6_addr.s6_addr[3] = 0;
- }
-
- return (sockaddr_to_text((struct sockaddr *)&sa_in6));
-}
-
-int
-text_to_mailaddr(struct mailaddr *maddr, const char *email)
-{
- char *username;
- char *hostname;
- char buffer[LINE_MAX];
-
- if (strlcpy(buffer, email, sizeof buffer) >= sizeof buffer)
- return 0;
-
- memset(maddr, 0, sizeof *maddr);
-
- username = buffer;
- hostname = strrchr(username, '@');
-
- if (hostname == NULL) {
- if (strlcpy(maddr->user, username, sizeof maddr->user)
- >= sizeof maddr->user)
- return 0;
- }
- else if (username == hostname) {
- *hostname++ = '\0';
- if (strlcpy(maddr->domain, hostname, sizeof maddr->domain)
- >= sizeof maddr->domain)
- return 0;
- }
- else {
- *hostname++ = '\0';
- if (strlcpy(maddr->user, username, sizeof maddr->user)
- >= sizeof maddr->user)
- return 0;
- if (strlcpy(maddr->domain, hostname, sizeof maddr->domain)
- >= sizeof maddr->domain)
- return 0;
- }
-
- return 1;
-}
-
-const char *
-mailaddr_to_text(const struct mailaddr *maddr)
-{
- static char buffer[LINE_MAX];
-
- (void)strlcpy(buffer, maddr->user, sizeof buffer);
- (void)strlcat(buffer, "@", sizeof buffer);
- if (strlcat(buffer, maddr->domain, sizeof buffer) >= sizeof buffer)
- return NULL;
-
- return buffer;
-}
-
-
-const char *
-sa_to_text(const struct sockaddr *sa)
-{
- static char buf[NI_MAXHOST + 5];
- char *p;
-
- buf[0] = '\0';
- p = buf;
-
- if (sa->sa_family == AF_LOCAL)
- (void)strlcpy(buf, "local", sizeof buf);
- else if (sa->sa_family == AF_INET) {
- in_addr_t addr;
-
- addr = ((const struct sockaddr_in *)sa)->sin_addr.s_addr;
- addr = ntohl(addr);
- (void)bsnprintf(p, NI_MAXHOST, "%d.%d.%d.%d",
- (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
- }
- else if (sa->sa_family == AF_INET6) {
- const struct sockaddr_in6 *in6;
- const struct in6_addr *in6_addr;
-
- in6 = (const struct sockaddr_in6 *)sa;
- p = buf;
- in6_addr = &in6->sin6_addr;
- (void)bsnprintf(p, NI_MAXHOST, "[%s]", in6addr_to_text(in6_addr));
- }
-
- return (buf);
-}
-
-const char *
-ss_to_text(const struct sockaddr_storage *ss)
-{
- return (sa_to_text((const struct sockaddr*)ss));
-}
-
-const char *
-time_to_text(time_t when)
-{
- struct tm *lt;
- static char buf[40];
- char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
- char *month[] = {"Jan","Feb","Mar","Apr","May","Jun",
- "Jul","Aug","Sep","Oct","Nov","Dec"};
- char *tz;
- long offset;
-
- lt = localtime(&when);
- if (lt == NULL || when == 0)
- fatalx("time_to_text: localtime");
-
- offset = lt->tm_gmtoff;
- tz = lt->tm_zone;
-
- /* We do not use strftime because it is subject to locale substitution*/
- if (!bsnprintf(buf, sizeof(buf),
- "%s, %d %s %d %02d:%02d:%02d %c%02d%02d (%s)",
- day[lt->tm_wday], lt->tm_mday, month[lt->tm_mon],
- lt->tm_year + 1900,
- lt->tm_hour, lt->tm_min, lt->tm_sec,
- offset >= 0 ? '+' : '-',
- abs((int)offset / 3600),
- abs((int)offset % 3600) / 60,
- tz))
- fatalx("time_to_text: bsnprintf");
-
- return buf;
-}
-
-const char *
-duration_to_text(time_t t)
-{
- static char dst[64];
- char buf[64];
- int h, m, s;
- long long d;
-
- if (t == 0) {
- (void)strlcpy(dst, "0s", sizeof dst);
- return (dst);
- }
-
- dst[0] = '\0';
- if (t < 0) {
- (void)strlcpy(dst, "-", sizeof dst);
- t = -t;
- }
-
- s = t % 60;
- t /= 60;
- m = t % 60;
- t /= 60;
- h = t % 24;
- d = t / 24;
-
- if (d) {
- (void)snprintf(buf, sizeof buf, "%lldd", d);
- (void)strlcat(dst, buf, sizeof dst);
- }
- if (h) {
- (void)snprintf(buf, sizeof buf, "%dh", h);
- (void)strlcat(dst, buf, sizeof dst);
- }
- if (m) {
- (void)snprintf(buf, sizeof buf, "%dm", m);
- (void)strlcat(dst, buf, sizeof dst);
- }
- if (s) {
- (void)snprintf(buf, sizeof buf, "%ds", s);
- (void)strlcat(dst, buf, sizeof dst);
- }
-
- return (dst);
-}
-
-int
-text_to_netaddr(struct netaddr *netaddr, const char *s)
-{
- struct sockaddr_storage ss;
- struct sockaddr_in ssin;
- struct sockaddr_in6 ssin6;
- int bits;
- char buf[NI_MAXHOST];
- size_t len;
-
- memset(&ssin, 0, sizeof(struct sockaddr_in));
- memset(&ssin6, 0, sizeof(struct sockaddr_in6));
-
- if (strncasecmp("IPv6:", s, 5) == 0)
- s += 5;
-
- bits = inet_net_pton(AF_INET, s, &ssin.sin_addr,
- sizeof(struct in_addr));
- if (bits != -1) {
- ssin.sin_family = AF_INET;
- memcpy(&ss, &ssin, sizeof(ssin));
- ss.ss_len = sizeof(struct sockaddr_in);
- } else {
- if (s[0] != '[') {
- if ((len = strlcpy(buf, s, sizeof buf)) >= sizeof buf)
- return 0;
- }
- else {
- s++;
- if (strncasecmp("IPv6:", s, 5) == 0)
- s += 5;
- if ((len = strlcpy(buf, s, sizeof buf)) >= sizeof buf)
- return 0;
- if (buf[len-1] != ']')
- return 0;
- buf[len-1] = 0;
- }
- bits = inet_net_pton(AF_INET6, buf, &ssin6.sin6_addr,
- sizeof(struct in6_addr));
- if (bits == -1)
- return 0;
- ssin6.sin6_family = AF_INET6;
- memcpy(&ss, &ssin6, sizeof(ssin6));
- ss.ss_len = sizeof(struct sockaddr_in6);
- }
-
- netaddr->ss = ss;
- netaddr->bits = bits;
- return 1;
-}
-
-int
-text_to_relayhost(struct relayhost *relay, const char *s)
-{
- static const struct schema {
- const char *name;
- int tls;
- uint16_t flags;
- uint16_t port;
- } schemas [] = {
- /*
- * new schemas should be *appended* otherwise the default
- * schema index needs to be updated later in this function.
- */
- { "smtp://", RELAY_TLS_OPPORTUNISTIC, 0, 25 },
- { "smtp+tls://", RELAY_TLS_STARTTLS, 0, 25 },
- { "smtp+notls://", RELAY_TLS_NO, 0, 25 },
- /* need to specify an explicit port for LMTP */
- { "lmtp://", RELAY_TLS_NO, RELAY_LMTP, 0 },
- { "smtps://", RELAY_TLS_SMTPS, 0, 465 }
- };
- const char *errstr = NULL;
- char *p, *q;
- char buffer[1024];
- char *beg, *end;
- size_t i;
- size_t len;
-
- memset(buffer, 0, sizeof buffer);
- if (strlcpy(buffer, s, sizeof buffer) >= sizeof buffer)
- return 0;
-
- for (i = 0; i < nitems(schemas); ++i)
- if (strncasecmp(schemas[i].name, s,
- strlen(schemas[i].name)) == 0)
- break;
-
- if (i == nitems(schemas)) {
- /* there is a schema, but it's not recognized */
- if (strstr(buffer, "://"))
- return 0;
-
- /* no schema, default to smtp:// */
- i = 0;
- p = buffer;
- }
- else
- p = buffer + strlen(schemas[i].name);
-
- relay->tls = schemas[i].tls;
- relay->flags = schemas[i].flags;
- relay->port = schemas[i].port;
-
- /* first, we extract the label if any */
- if ((q = strchr(p, '@')) != NULL) {
- *q = 0;
- if (strlcpy(relay->authlabel, p, sizeof (relay->authlabel))
- >= sizeof (relay->authlabel))
- return 0;
- p = q + 1;
- }
-
- /* then, we extract the mail exchanger */
- beg = end = p;
- if (*beg == '[') {
- if ((end = strchr(beg, ']')) == NULL)
- return 0;
- /* skip ']', it has to be included in the relay hostname */
- ++end;
- len = end - beg;
- }
- else {
- for (end = beg; *end; ++end)
- if (!isalnum((unsigned char)*end) &&
- *end != '_' && *end != '.' && *end != '-')
- break;
- len = end - beg;
- }
- if (len >= sizeof relay->hostname)
- return 0;
- for (i = 0; i < len; ++i)
- relay->hostname[i] = beg[i];
- relay->hostname[i] = 0;
-
- /* finally, we extract the port */
- p = beg + len;
- if (*p == ':') {
- relay->port = strtonum(p+1, 1, IPPORT_HILASTAUTO, &errstr);
- if (errstr)
- return 0;
- }
-
- if (!valid_domainpart(relay->hostname))
- return 0;
- if ((relay->flags & RELAY_LMTP) && (relay->port == 0))
- return 0;
- if (relay->authlabel[0]) {
- /* disallow auth on non-tls scheme. */
- if (relay->tls != RELAY_TLS_STARTTLS &&
- relay->tls != RELAY_TLS_SMTPS)
- return 0;
- relay->flags |= RELAY_AUTH;
- }
-
- return 1;
-}
-
-uint64_t
-text_to_evpid(const char *s)
-{
- uint64_t ulval;
- char *ep;
-
- errno = 0;
- ulval = strtoull(s, &ep, 16);
- if (s[0] == '\0' || *ep != '\0')
- return 0;
- if (errno == ERANGE && ulval == ULLONG_MAX)
- return 0;
- if (ulval == 0)
- return 0;
- return (ulval);
-}
-
-uint32_t
-text_to_msgid(const char *s)
-{
- uint64_t ulval;
- char *ep;
-
- errno = 0;
- ulval = strtoull(s, &ep, 16);
- if (s[0] == '\0' || *ep != '\0')
- return 0;
- if (errno == ERANGE && ulval == ULLONG_MAX)
- return 0;
- if (ulval == 0)
- return 0;
- if (ulval > 0xffffffff)
- return 0;
- return (ulval & 0xffffffff);
-}
-
-const char *
-rule_to_text(struct rule *r)
-{
- static char buf[4096];
-
- memset(buf, 0, sizeof buf);
- (void)strlcpy(buf, "match", sizeof buf);
- if (r->flag_tag) {
- if (r->flag_tag < 0)
- (void)strlcat(buf, " !", sizeof buf);
- (void)strlcat(buf, " tag ", sizeof buf);
- (void)strlcat(buf, r->table_tag, sizeof buf);
- }
-
- if (r->flag_from) {
- if (r->flag_from < 0)
- (void)strlcat(buf, " !", sizeof buf);
- if (r->flag_from_socket)
- (void)strlcat(buf, " from socket", sizeof buf);
- else if (r->flag_from_rdns) {
- (void)strlcat(buf, " from rdns", sizeof buf);
- if (r->table_from) {
- (void)strlcat(buf, " ", sizeof buf);
- (void)strlcat(buf, r->table_from, sizeof buf);
- }
- }
- else if (strcmp(r->table_from, "<anyhost>") == 0)
- (void)strlcat(buf, " from any", sizeof buf);
- else if (strcmp(r->table_from, "<localhost>") == 0)
- (void)strlcat(buf, " from local", sizeof buf);
- else {
- (void)strlcat(buf, " from src ", sizeof buf);
- (void)strlcat(buf, r->table_from, sizeof buf);
- }
- }
-
- if (r->flag_for) {
- if (r->flag_for < 0)
- (void)strlcat(buf, " !", sizeof buf);
- if (strcmp(r->table_for, "<anydestination>") == 0)
- (void)strlcat(buf, " for any", sizeof buf);
- else if (strcmp(r->table_for, "<localnames>") == 0)
- (void)strlcat(buf, " for local", sizeof buf);
- else {
- (void)strlcat(buf, " for domain ", sizeof buf);
- (void)strlcat(buf, r->table_for, sizeof buf);
- }
- }
-
- if (r->flag_smtp_helo) {
- if (r->flag_smtp_helo < 0)
- (void)strlcat(buf, " !", sizeof buf);
- (void)strlcat(buf, " helo ", sizeof buf);
- (void)strlcat(buf, r->table_smtp_helo, sizeof buf);
- }
-
- if (r->flag_smtp_auth) {
- if (r->flag_smtp_auth < 0)
- (void)strlcat(buf, " !", sizeof buf);
- (void)strlcat(buf, " auth", sizeof buf);
- if (r->table_smtp_auth) {
- (void)strlcat(buf, " ", sizeof buf);
- (void)strlcat(buf, r->table_smtp_auth, sizeof buf);
- }
- }
-
- if (r->flag_smtp_starttls) {
- if (r->flag_smtp_starttls < 0)
- (void)strlcat(buf, " !", sizeof buf);
- (void)strlcat(buf, " tls", sizeof buf);
- }
-
- if (r->flag_smtp_mail_from) {
- if (r->flag_smtp_mail_from < 0)
- (void)strlcat(buf, " !", sizeof buf);
- (void)strlcat(buf, " mail-from ", sizeof buf);
- (void)strlcat(buf, r->table_smtp_mail_from, sizeof buf);
- }
-
- if (r->flag_smtp_rcpt_to) {
- if (r->flag_smtp_rcpt_to < 0)
- (void)strlcat(buf, " !", sizeof buf);
- (void)strlcat(buf, " rcpt-to ", sizeof buf);
- (void)strlcat(buf, r->table_smtp_rcpt_to, sizeof buf);
- }
- (void)strlcat(buf, " action ", sizeof buf);
- if (r->reject)
- (void)strlcat(buf, "reject", sizeof buf);
- else
- (void)strlcat(buf, r->dispatcher, sizeof buf);
- return buf;
-}
-
-
-int
-text_to_userinfo(struct userinfo *userinfo, const char *s)
-{
- char buf[PATH_MAX];
- char *p;
- const char *errstr;
-
- memset(buf, 0, sizeof buf);
- p = buf;
- while (*s && *s != ':')
- *p++ = *s++;
- if (*s++ != ':')
- goto error;
-
- if (strlcpy(userinfo->username, buf,
- sizeof userinfo->username) >= sizeof userinfo->username)
- goto error;
-
- memset(buf, 0, sizeof buf);
- p = buf;
- while (*s && *s != ':')
- *p++ = *s++;
- if (*s++ != ':')
- goto error;
- userinfo->uid = strtonum(buf, 0, UID_MAX, &errstr);
- if (errstr)
- goto error;
-
- memset(buf, 0, sizeof buf);
- p = buf;
- while (*s && *s != ':')
- *p++ = *s++;
- if (*s++ != ':')
- goto error;
- userinfo->gid = strtonum(buf, 0, GID_MAX, &errstr);
- if (errstr)
- goto error;
-
- if (strlcpy(userinfo->directory, s,
- sizeof userinfo->directory) >= sizeof userinfo->directory)
- goto error;
-
- return 1;
-
-error:
- return 0;
-}
-
-int
-text_to_credentials(struct credentials *creds, const char *s)
-{
- char *p;
- char buffer[LINE_MAX];
- size_t offset;
-
- p = strchr(s, ':');
- if (p == NULL) {
- creds->username[0] = '\0';
- if (strlcpy(creds->password, s, sizeof creds->password)
- >= sizeof creds->password)
- return 0;
- return 1;
- }
-
- offset = p - s;
-
- memset(buffer, 0, sizeof buffer);
- if (strlcpy(buffer, s, sizeof buffer) >= sizeof buffer)
- return 0;
- p = buffer + offset;
- *p = '\0';
-
- if (strlcpy(creds->username, buffer, sizeof creds->username)
- >= sizeof creds->username)
- return 0;
- if (strlcpy(creds->password, p+1, sizeof creds->password)
- >= sizeof creds->password)
- return 0;
-
- return 1;
-}
-
-int
-text_to_expandnode(struct expandnode *expandnode, const char *s)
-{
- size_t l;
-
- l = strlen(s);
- if (alias_is_error(expandnode, s, l) ||
- alias_is_include(expandnode, s, l) ||
- alias_is_filter(expandnode, s, l) ||
- alias_is_filename(expandnode, s, l) ||
- alias_is_address(expandnode, s, l) ||
- alias_is_username(expandnode, s, l))
- return (1);
-
- return (0);
-}
-
-const char *
-expandnode_to_text(struct expandnode *expandnode)
-{
- switch (expandnode->type) {
- case EXPAND_FILTER:
- case EXPAND_FILENAME:
- case EXPAND_INCLUDE:
- case EXPAND_ERROR:
- case EXPAND_USERNAME:
- return expandnode->u.user;
- case EXPAND_ADDRESS:
- return mailaddr_to_text(&expandnode->u.mailaddr);
- case EXPAND_INVALID:
- break;
- }
-
- return NULL;
-}
-
-/******/
-static int
-alias_is_filter(struct expandnode *alias, const char *line, size_t len)
-{
- int v = 0;
-
- if (*line == '"')
- v = 1;
- if (*(line+v) == '|') {
- if (strlcpy(alias->u.buffer, line + v + 1,
- sizeof(alias->u.buffer)) >= sizeof(alias->u.buffer))
- return 0;
- if (v) {
- v = strlen(alias->u.buffer);
- if (v == 0)
- return (0);
- if (alias->u.buffer[v-1] != '"')
- return (0);
- alias->u.buffer[v-1] = '\0';
- }
- alias->type = EXPAND_FILTER;
- return (1);
- }
- return (0);
-}
-
-static int
-alias_is_username(struct expandnode *alias, const char *line, size_t len)
-{
- memset(alias, 0, sizeof *alias);
-
- if (strlcpy(alias->u.user, line,
- sizeof(alias->u.user)) >= sizeof(alias->u.user))
- return 0;
-
- while (*line) {
- if (!isalnum((unsigned char)*line) &&
- *line != '_' && *line != '.' && *line != '-' && *line != '+')
- return 0;
- ++line;
- }
-
- alias->type = EXPAND_USERNAME;
- return 1;
-}
-
-static int
-alias_is_address(struct expandnode *alias, const char *line, size_t len)
-{
- char *domain;
-
- memset(alias, 0, sizeof *alias);
-
- if (len < 3) /* x@y */
- return 0;
-
- domain = strchr(line, '@');
- if (domain == NULL)
- return 0;
-
- /* @ cannot start or end an address */
- if (domain == line || domain == line + len - 1)
- return 0;
-
- /* scan pre @ for disallowed chars */
- *domain++ = '\0';
- (void)strlcpy(alias->u.mailaddr.user, line, sizeof(alias->u.mailaddr.user));
- (void)strlcpy(alias->u.mailaddr.domain, domain,
- sizeof(alias->u.mailaddr.domain));
-
- while (*line) {
- char allowedset[] = "!#$%*/?|^{}`~&'+-=_.";
- if (!isalnum((unsigned char)*line) &&
- strchr(allowedset, *line) == NULL)
- return 0;
- ++line;
- }
-
- while (*domain) {
- char allowedset[] = "-.";
- if (!isalnum((unsigned char)*domain) &&
- strchr(allowedset, *domain) == NULL)
- return 0;
- ++domain;
- }
-
- alias->type = EXPAND_ADDRESS;
- return 1;
-}
-
-static int
-alias_is_filename(struct expandnode *alias, const char *line, size_t len)
-{
- memset(alias, 0, sizeof *alias);
-
- if (*line != '/')
- return 0;
-
- if (strlcpy(alias->u.buffer, line,
- sizeof(alias->u.buffer)) >= sizeof(alias->u.buffer))
- return 0;
- alias->type = EXPAND_FILENAME;
- return 1;
-}
-
-static int
-alias_is_include(struct expandnode *alias, const char *line, size_t len)
-{
- size_t skip;
-
- memset(alias, 0, sizeof *alias);
-
- if (strncasecmp(":include:", line, 9) == 0)
- skip = 9;
- else if (strncasecmp("include:", line, 8) == 0)
- skip = 8;
- else
- return 0;
-
- if (!alias_is_filename(alias, line + skip, len - skip))
- return 0;
-
- alias->type = EXPAND_INCLUDE;
- return 1;
-}
-
-static int
-alias_is_error(struct expandnode *alias, const char *line, size_t len)
-{
- size_t skip;
-
- memset(alias, 0, sizeof *alias);
-
- if (strncasecmp(":error:", line, 7) == 0)
- skip = 7;
- else if (strncasecmp("error:", line, 6) == 0)
- skip = 6;
- else
- return 0;
-
- if (strlcpy(alias->u.buffer, line + skip,
- sizeof(alias->u.buffer)) >= sizeof(alias->u.buffer))
- return 0;
-
- if (strlen(alias->u.buffer) < 5)
- return 0;
-
- /* [45][0-9]{2} [a-zA-Z0-9].* */
- if (alias->u.buffer[3] != ' ' ||
- !isalnum((unsigned char)alias->u.buffer[4]) ||
- (alias->u.buffer[0] != '4' && alias->u.buffer[0] != '5') ||
- !isdigit((unsigned char)alias->u.buffer[1]) ||
- !isdigit((unsigned char)alias->u.buffer[2]))
- return 0;
-
- alias->type = EXPAND_ERROR;
- return 1;
-}