1 /* $OpenBSD: to.c,v 1.17 2014/04/19 14:27:29 gilles Exp $ */
2
3 /*
4 * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
5 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
6 * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 #include <sys/types.h>
22 #include <sys/queue.h>
23 #include <sys/tree.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/resource.h>
27
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30
31 #include <ctype.h>
32 #include <err.h>
33 #include <errno.h>
34 #include <event.h>
35 #include <fcntl.h>
36 #include <fts.h>
37 #include <imsg.h>
38 #include <inttypes.h>
39 #include <libgen.h>
40 #include <netdb.h>
41 #include <pwd.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48
49 #include "smtpd-defines.h"
50 #include <smtpd-api.h>
51 #include "log.h"
52
53 static const char *in6addr_to_text(const struct in6_addr *);
54
55 const char *
sockaddr_to_text(struct sockaddr * sa)56 sockaddr_to_text(struct sockaddr *sa)
57 {
58 static char buf[NI_MAXHOST];
59
60 if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0,
61 NI_NUMERICHOST))
62 return ("(unknown)");
63 else
64 return (buf);
65 }
66
67 static const char *
in6addr_to_text(const struct in6_addr * addr)68 in6addr_to_text(const struct in6_addr *addr)
69 {
70 struct sockaddr_in6 sa_in6;
71 uint16_t tmp16;
72
73 memset(&sa_in6, 0, sizeof(sa_in6));
74 sa_in6.sin6_len = sizeof(sa_in6);
75 sa_in6.sin6_family = AF_INET6;
76 memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
77
78 /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
79 if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
80 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
81 memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
82 sa_in6.sin6_scope_id = ntohs(tmp16);
83 sa_in6.sin6_addr.s6_addr[2] = 0;
84 sa_in6.sin6_addr.s6_addr[3] = 0;
85 }
86
87 return (sockaddr_to_text((struct sockaddr *)&sa_in6));
88 }
89
90 int
text_to_mailaddr(struct mailaddr * maddr,const char * email)91 text_to_mailaddr(struct mailaddr *maddr, const char *email)
92 {
93 char *username;
94 char *hostname;
95 char buffer[LINE_MAX];
96
97 if (strlcpy(buffer, email, sizeof buffer) >= sizeof buffer)
98 return 0;
99
100 memset(maddr, 0, sizeof *maddr);
101
102 username = buffer;
103 hostname = strrchr(username, '@');
104
105 if (hostname == NULL) {
106 if (strlcpy(maddr->user, username, sizeof maddr->user)
107 >= sizeof maddr->user)
108 return 0;
109 }
110 else if (username == hostname) {
111 *hostname++ = '\0';
112 if (strlcpy(maddr->domain, hostname, sizeof maddr->domain)
113 >= sizeof maddr->domain)
114 return 0;
115 }
116 else {
117 *hostname++ = '\0';
118 if (strlcpy(maddr->user, username, sizeof maddr->user)
119 >= sizeof maddr->user)
120 return 0;
121 if (strlcpy(maddr->domain, hostname, sizeof maddr->domain)
122 >= sizeof maddr->domain)
123 return 0;
124 }
125
126 return 1;
127 }
128
129 const char *
mailaddr_to_text(const struct mailaddr * maddr)130 mailaddr_to_text(const struct mailaddr *maddr)
131 {
132 static char buffer[LINE_MAX];
133
134 (void)strlcpy(buffer, maddr->user, sizeof buffer);
135 (void)strlcat(buffer, "@", sizeof buffer);
136 if (strlcat(buffer, maddr->domain, sizeof buffer) >= sizeof buffer)
137 return NULL;
138
139 return buffer;
140 }
141
142
143 const char *
sa_to_text(const struct sockaddr * sa)144 sa_to_text(const struct sockaddr *sa)
145 {
146 static char buf[NI_MAXHOST + 5];
147 char *p;
148
149 buf[0] = '\0';
150 p = buf;
151
152 if (sa->sa_family == AF_LOCAL)
153 (void)strlcpy(buf, "local", sizeof buf);
154 else if (sa->sa_family == AF_INET) {
155 in_addr_t addr;
156
157 addr = ((const struct sockaddr_in *)sa)->sin_addr.s_addr;
158 addr = ntohl(addr);
159 (void)snprintf(p, NI_MAXHOST, "%d.%d.%d.%d",
160 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
161 (addr >> 8) & 0xff, addr & 0xff);
162 }
163 else if (sa->sa_family == AF_INET6) {
164 const struct sockaddr_in6 *in6;
165 const struct in6_addr *in6_addr;
166
167 in6 = (const struct sockaddr_in6 *)sa;
168 (void)strlcpy(buf, "IPv6:", sizeof(buf));
169 p = buf + 5;
170 in6_addr = &in6->sin6_addr;
171 (void)snprintf(p, NI_MAXHOST, "%s", in6addr_to_text(in6_addr));
172 }
173
174 return (buf);
175 }
176
177 const char *
ss_to_text(const struct sockaddr_storage * ss)178 ss_to_text(const struct sockaddr_storage *ss)
179 {
180 return (sa_to_text((const struct sockaddr*)ss));
181 }
182
183 const char *
time_to_text(time_t when)184 time_to_text(time_t when)
185 {
186 struct tm *lt;
187 static char buf[40];
188 char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
189 char *month[] = {"Jan","Feb","Mar","Apr","May","Jun",
190 "Jul","Aug","Sep","Oct","Nov","Dec"};
191 int ret;
192
193 lt = localtime(&when);
194 if (lt == NULL || when == 0)
195 fatalx("time_to_text: localtime");
196
197 /* We do not use strftime because it is subject to locale substitution*/
198 ret = snprintf(buf, sizeof(buf),
199 "%s, %d %s %d %02d:%02d:%02d %c%02d%02d (%s)",
200 day[lt->tm_wday], lt->tm_mday, month[lt->tm_mon],
201 lt->tm_year + 1900,
202 lt->tm_hour, lt->tm_min, lt->tm_sec,
203 lt->tm_gmtoff >= 0 ? '+' : '-',
204 abs((int)lt->tm_gmtoff / 3600),
205 abs((int)lt->tm_gmtoff % 3600) / 60,
206 lt->tm_zone);
207 if (ret == -1 || ret >= sizeof (buf))
208 fatalx("time_to_text: snprintf");
209
210 return buf;
211 }
212
213 const char *
duration_to_text(time_t t)214 duration_to_text(time_t t)
215 {
216 static char dst[64];
217 char buf[64];
218 int h, m, s;
219 long long d;
220
221 if (t == 0) {
222 (void)strlcpy(dst, "0s", sizeof dst);
223 return (dst);
224 }
225
226 dst[0] = '\0';
227 if (t < 0) {
228 (void)strlcpy(dst, "-", sizeof dst);
229 t = -t;
230 }
231
232 s = t % 60;
233 t /= 60;
234 m = t % 60;
235 t /= 60;
236 h = t % 24;
237 d = t / 24;
238
239 if (d) {
240 (void)snprintf(buf, sizeof buf, "%lldd", d);
241 (void)strlcat(dst, buf, sizeof dst);
242 }
243 if (h) {
244 (void)snprintf(buf, sizeof buf, "%dh", h);
245 (void)strlcat(dst, buf, sizeof dst);
246 }
247 if (m) {
248 (void)snprintf(buf, sizeof buf, "%dm", m);
249 (void)strlcat(dst, buf, sizeof dst);
250 }
251 if (s) {
252 (void)snprintf(buf, sizeof buf, "%ds", s);
253 (void)strlcat(dst, buf, sizeof dst);
254 }
255
256 return (dst);
257 }
258
259 uint64_t
text_to_evpid(const char * s)260 text_to_evpid(const char *s)
261 {
262 uint64_t ulval;
263 char *ep;
264
265 errno = 0;
266 ulval = strtoull(s, &ep, 16);
267 if (s[0] == '\0' || *ep != '\0')
268 return 0;
269 if (errno == ERANGE && ulval == ULLONG_MAX)
270 return 0;
271 if (ulval == 0)
272 return 0;
273 return (ulval);
274 }
275
276 uint32_t
text_to_msgid(const char * s)277 text_to_msgid(const char *s)
278 {
279 uint64_t ulval;
280 char *ep;
281
282 errno = 0;
283 ulval = strtoull(s, &ep, 16);
284 if (s[0] == '\0' || *ep != '\0')
285 return 0;
286 if (errno == ERANGE && ulval == ULLONG_MAX)
287 return 0;
288 if (ulval == 0)
289 return 0;
290 if (ulval > 0xffffffff)
291 return 0;
292 return (ulval & 0xffffffff);
293 }
294