1 /*
2  * Copyright (c) 2014 Gilles Chehade <gilles@poolp.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "includes.h"
18 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 
23 #include <ctype.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30 #include <unistd.h>
31 
32 #include <smtpd-api.h>
33 
34 static char	       *config;
35 static int		sock = -1;
36 static FILE	       *sockstream;
37 #define	REPLYBUFFERSIZE	100000
38 static char		repbuffer[REPLYBUFFERSIZE+1];
39 
40 enum socketmap_reply{
41 	SM_OK = 0,
42 	SM_NOTFOUND,
43 	SM_TEMP,
44 	SM_TIMEOUT,
45 	SM_PERM,
46 };
47 
48 static int
table_socketmap_connect(const char * s)49 table_socketmap_connect(const char *s)
50 {
51 	struct sockaddr_un	sun;
52 
53 	if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
54 		log_warn("warn: socket");
55 		goto err;
56 	}
57 
58 	memset(&sun, 0, sizeof sun);
59 	sun.sun_family = AF_UNIX;
60 	if (strlcpy(sun.sun_path, s, sizeof(sun.sun_path)) >=
61 	    sizeof(sun.sun_path)) {
62 		log_warnx("warn: socket path too long");
63 		goto err;
64 	}
65 
66 	if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
67 		log_warn("warn: connect");
68 		goto err;
69 	}
70 
71 	if ((sockstream = fdopen(sock, "w+")) == NULL) {
72 		log_warn("warn: fdopen");
73 		goto err;
74 	}
75 
76 	return 1;
77 
78 err:
79 	if (sock == -1) {
80 		close(sock);
81 		sock = -1;
82 	}
83 	return 0;
84 }
85 
86 static enum socketmap_reply
table_socketmap_query(const char * name,const char * key)87 table_socketmap_query(const char *name, const char *key)
88 {
89 	char   *buf = NULL;
90 	size_t	sz = 0;
91 	ssize_t	len;
92 	int	ret = SM_PERM;
93 
94 	memset(repbuffer, 0, sizeof repbuffer);
95 	fprintf(sockstream, "%s %s\n", name, key);
96 	fflush(sockstream);
97 
98 	if ((len = getline(&buf, &sz, sockstream)) == -1) {
99 		log_warnx("warn: socketmap has lost its socket");
100 		(void)strlcpy(repbuffer, "lost connection to socket", sizeof repbuffer);
101 		ret = SM_PERM;
102 		goto err;
103 	}
104 	if (buf[len - 1] == '\n')
105 		buf[len - 1] = '\0';
106 
107 	if (strlcpy(repbuffer, buf, sizeof repbuffer) >= sizeof repbuffer) {
108 		log_warnx("warn: socketmap reply too large (>%zu bytes)",
109 			sizeof repbuffer);
110 		(void)strlcpy(repbuffer, "socketmap reply too large", sizeof repbuffer);
111 		ret = SM_PERM;
112 		goto err;
113 	}
114 
115 	if (strncasecmp(repbuffer, "OK ", 3) == 0) {
116 		ret = SM_OK;
117 		memmove(repbuffer, repbuffer+3, strlen(repbuffer)-2);
118 	}
119 	else if (strncasecmp(repbuffer, "NOTFOUND ", 9) == 0) {
120 		ret = SM_NOTFOUND;
121 		memmove(repbuffer, repbuffer+9, strlen(repbuffer)-8);
122 	}
123 	else if (strncasecmp(repbuffer, "TEMP ", 5) == 0) {
124 		ret = SM_TEMP;
125 		memmove(repbuffer, repbuffer+5, strlen(repbuffer)-4);
126 	}
127 	else if (strncasecmp(repbuffer, "TIMEOUT ", 8) == 0) {
128 		ret = SM_TIMEOUT;
129 		memmove(repbuffer, repbuffer+8, strlen(repbuffer)-7);
130 	}
131 	else if (strncasecmp(repbuffer, "PERM ", 5) == 0) {
132 		ret = SM_PERM;
133 		memmove(repbuffer, repbuffer+5, strlen(repbuffer)-4);
134 	}
135 	else {
136 		ret = SM_PERM;
137 		(void)strlcpy(repbuffer, "unrecognized socketmap reply", sizeof repbuffer);
138 	}
139 
140 err:
141 	free(buf);
142 	return ret;
143 }
144 
145 static int
table_socketmap_update(void)146 table_socketmap_update(void)
147 {
148 	return 1;
149 }
150 
151 static int
table_socketmap_check(int service,struct dict * params,const char * key)152 table_socketmap_check(int service, struct dict *params, const char *key)
153 {
154 	return -1;
155 }
156 
157 static int
table_socketmap_lookup(int service,struct dict * params,const char * key,char * dst,size_t sz)158 table_socketmap_lookup(int service, struct dict *params, const char *key, char *dst, size_t sz)
159 {
160 	int			r;
161 	enum socketmap_reply	rep;
162 
163 	rep = table_socketmap_query(table_api_get_name(), key);
164 	if (rep == SM_NOTFOUND)
165 		return 0;
166 	if (rep != SM_OK) {
167 		log_warnx("warn: %s", repbuffer);
168 		return -1;
169 	}
170 	if (strlcpy(dst, repbuffer, sz) >= sz) {
171 		log_warnx("warn: result too large");
172 		return -1;
173 	}
174 
175 	r = 1;
176 	switch(service) {
177 	case K_ALIAS:
178 	case K_CREDENTIALS:
179 	case K_USERINFO:
180 	case K_DOMAIN:
181 	case K_NETADDR:
182 	case K_SOURCE:
183 	case K_MAILADDR:
184 	case K_ADDRNAME:
185 		break;
186 	default:
187 		log_warnx("warn: unknown service %d", service);
188 		r = -1;
189 	}
190 
191 	return r;
192 }
193 
194 static int
table_socketmap_fetch(int service,struct dict * params,char * key,size_t sz)195 table_socketmap_fetch(int service, struct dict *params, char *key, size_t sz)
196 {
197 	return -1;
198 }
199 
200 int
main(int argc,char ** argv)201 main(int argc, char **argv)
202 {
203 	int ch;
204 
205 	log_init(1);
206 	log_verbose(~0);
207 
208 	while ((ch = getopt(argc, argv, "")) != -1) {
209 		switch (ch) {
210 		default:
211 			fatalx("bad option");
212 			/* NOTREACHED */
213 		}
214 	}
215 	argc -= optind;
216 	argv += optind;
217 
218 	if (argc != 1)
219 		fatalx("bogus argument(s)");
220 
221 
222 	config = argv[0];
223 
224 	if (table_socketmap_connect(config) == 0)
225 		fatalx("error connecting to %s", config);
226 
227 	table_api_on_update(table_socketmap_update);
228 	table_api_on_check(table_socketmap_check);
229 	table_api_on_lookup(table_socketmap_lookup);
230 	table_api_on_fetch(table_socketmap_fetch);
231 	table_api_dispatch();
232 
233 	return 0;
234 }
235