1 /*
2  * foobar.c
3  * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
4  * All rights reserved.
5  *
6  * RFC 1639 (FTP Operation Over Big Address Records)
7  * RFC 2428 (FTP Extensions for IPv6 and NATs)
8  * RFC 959  (FTP)
9  * RFC 1700 (Assigned Numbers)
10  *
11  * $Id: foobar.c,v 1.15 2015/03/14 06:11:24 marc Exp marc $
12  *
13  */
14 
15 #include "headers.h"
16 
17 static const char rcsid[] __attribute__ ((used)) = "$Id: foobar.c,v 1.15 2015/03/14 06:11:24 marc Exp marc $";
18 
19 #define FOOBAR_AF_IP            4	/* IP (IPv4)              */
20 #define FOOBAR_AF_ST            5	/* ST Datagram Mode       */
21 #define FOOBAR_AF_SIP           6	/* SIP (IPv6)             */
22 #define FOOBAR_AF_TPIX          7	/* TP/IX                  */
23 #define FOOBAR_AF_PIP           8	/* PIP                    */
24 #define FOOBAR_AF_TUBA          9	/* TUBA                   */
25 #define FOOBAR_AF_IPX           16	/* Novell IPX             */
26 
27 #define RFC2428_AF_IP           1	/* IP (IP version 4)      */
28 #define RFC2428_AF_IP6          2	/* IP6 (IP version 6)     */
29 
30 struct foobar_af_mapping_s {
31     int foobar_af;
32     int af;
33 };
34 
35 struct foobar_af_mapping_s foobar_af_mapping[] = {
36 #ifdef AF_INET
37     {FOOBAR_AF_IP, AF_INET,},
38 #endif
39 #ifdef AF_INET6
40     {FOOBAR_AF_SIP, AF_INET6,},
41 #endif
42     {-1, -1,},
43 };
44 
45 struct rfc2428_af_mapping_s {
46     int rfc2428_af;
47     int af;
48 };
49 
50 struct rfc2428_af_mapping_s rfc2428_af_mapping[] = {
51 #ifdef AF_INET
52     {RFC2428_AF_IP, AF_INET,},
53 #endif
54 #ifdef AF_INET6
55     {RFC2428_AF_IP6, AF_INET6,},
56 #endif
57     {-1, -1,},
58 };
59 
foobar2af(int af)60 int foobar2af(int af)
61 {
62     struct foobar_af_mapping_s *m = foobar_af_mapping;
63     for (; m->foobar_af != -1; m++)
64 	if (m->foobar_af == af)
65 	    return m->af;
66     return -1;
67 }
68 
af2foobar(int af)69 int af2foobar(int af)
70 {
71     struct foobar_af_mapping_s *m = foobar_af_mapping;
72     for (; m->foobar_af != -1; m++)
73 	if (m->af == af)
74 	    return m->foobar_af;
75     return -1;
76 }
77 
rfc2428_2_af(int af)78 int rfc2428_2_af(int af)
79 {
80     struct rfc2428_af_mapping_s *m = rfc2428_af_mapping;
81 
82     for (; m->rfc2428_af != -1; m++)
83 	if (m->rfc2428_af == af)
84 	    return m->af;
85     return -1;
86 }
87 
print_rfc2428_families(char * s,size_t len)88 char *print_rfc2428_families(char *s, size_t len)
89 {
90     char *t = s;
91     struct rfc2428_af_mapping_s *m = rfc2428_af_mapping;
92 
93     for (; m->rfc2428_af != -1; m++) {
94 	if (s != t)
95 	    *t++ = ',';
96 	t += snprintf(t, (size_t) (s + len - t), "%d", m->rfc2428_af);
97     }
98     return s;
99 }
100 
print_foobar_families(char * s,size_t len)101 char *print_foobar_families(char *s, size_t len)
102 {
103     char *t = s;
104     struct foobar_af_mapping_s *m = foobar_af_mapping;
105 
106     for (; m->foobar_af != -1; m++) {
107 	if (s != t)
108 	    *t++ = ',';
109 	t += snprintf(t, (size_t) (s + len - t), "%d", m->foobar_af);
110     }
111     return s;
112 }
113 
af2rfc2428(int af)114 int af2rfc2428(int af)
115 {
116     struct rfc2428_af_mapping_s *m = rfc2428_af_mapping;
117     for (; m->rfc2428_af != -1; m++)
118 	if (m->af == af)
119 	    return m->rfc2428_af;
120     return -1;
121 }
122 
123 /* foobar_eval() -- evaluate <long-host-port> */
124 /* returns foobar address family, -1 on error */
125 /* char *long-host-port, void *addr, int *addrlen, void *port, int *portlen */
foobar_eval(sockaddr_union * sa,char * s)126 int foobar_eval(sockaddr_union * sa, char *s)
127 {
128     u_char arr[513];
129     int length = 0;
130 
131     DebugIn(DEBUG_COMMAND);
132 
133     if (!s) {
134 	Debug((DEBUG_COMMAND, "- %s: arg == NULL\n", __func__));
135 	return -1;
136     }
137 
138     memset(arr, 0, (size_t) 513);
139 
140     while (*s && isspace((int) *s))
141 	s++;
142 
143     for (; *s && !isspace((int) *s) && length < 512; s++)
144 	if (isdigit((int) *s)) {
145 	    arr[length] *= 10;
146 	    arr[length] += (u_char) * s - '0';
147 	} else if (*s == ',')
148 	    length++;
149 	else {
150 	    Debug((DEBUG_COMMAND, "- %s: invalid char\n", __func__));
151 	    return -1;
152 	}
153 
154     if (++length != arr[1] + 3 + arr[arr[1] + 2]) {
155 	Debug((DEBUG_COMMAND, "- %s: consistency check failed\n", __func__));
156 	return -1;
157     }
158 
159     memset(sa, 0, sizeof(sockaddr_union));
160     sa->sa.sa_family = foobar2af(arr[1]);
161 
162     switch (sa->sa.sa_family) {
163 #ifdef AF_INET
164     case AF_INET:
165 	memcpy(&sa->sin.sin_addr, arr + 2, (size_t) 4);
166 	memcpy(&sa->sin.sin_port, arr + arr[1] + 3, (size_t) 2);
167 	return sa->sa.sa_family;
168 #endif				/* AF_INET */
169 #ifdef AF_INET6
170     case AF_INET6:
171 	memcpy(&sa->sin6.sin6_addr, arr + 2, (size_t) 16);
172 	memcpy(&sa->sin6.sin6_port, arr + arr[1] + 3, (size_t) 2);
173 	return sa->sa.sa_family;
174 #endif				/* AF_INET6 */
175     }
176 
177     Debug((DEBUG_COMMAND, "- %s: af = %d\n", __func__, arr[0]));
178     return -2;
179 }
180 
foobar_str(sockaddr_union * sa,char * res,size_t reslen)181 char *foobar_str(sockaddr_union * sa, char *res, size_t reslen)
182 {
183     char *s = res;
184     int al, pl;
185     u_char *a, *p;
186 
187     switch (sa->sa.sa_family) {
188 #ifdef AF_INET
189     case AF_INET:
190 	al = 4, pl = 2;
191 	a = (u_char *) & sa->sin.sin_addr;
192 	p = (u_char *) & sa->sin.sin_port;
193 	break;
194 #endif
195 #ifdef AF_INET6
196     case AF_INET6:
197 	al = 16, pl = 2;
198 	a = (u_char *) & sa->sin6.sin6_addr;
199 	p = (u_char *) & sa->sin6.sin6_port;
200 	break;
201 #endif
202     default:
203 	return "(NULL)";
204     }
205 
206     s += snprintf(s, (size_t) (res + reslen - s), "%d,%u", af2foobar(sa->sa.sa_family), (u_int) al);
207 
208     while (al--)
209 	s += snprintf(s, (size_t) (res + reslen - s), ",%u", (u_int) * a++);
210 
211     s += snprintf(s, (size_t) (res + reslen - s), ",%u", (u_int) pl);
212 
213     while (pl--)
214 	s += snprintf(s, (size_t) (res + reslen - s), ",%u", (u_int) * p++);
215 
216     return res;
217 }
218 
rfc2428_eval(sockaddr_union * sa,char * in)219 int rfc2428_eval(sockaddr_union * sa, char *in)
220 {
221     char *s = alloca(strlen(in) + 1);
222     char delimiter;
223     int proto = -1;
224     char *net_prt = NULL;
225     char *net_addr = NULL;
226     char *tcp_port = NULL;
227     char *remainder = NULL;
228     int af;
229 
230     DebugIn(DEBUG_COMMAND);
231 
232     strcpy(s, in);
233 
234     if (!s) {
235 	Debug((DEBUG_COMMAND, "- %s: arg == NULL\n", __func__));
236 	return -1;
237     }
238 
239     delimiter = s[0];
240     net_prt = s + 1;
241     if ((net_addr = strchr(net_prt, delimiter))) {
242 	*net_addr++ = 0;
243 	if ((tcp_port = strchr(net_addr, delimiter))) {
244 	    *tcp_port++ = 0;
245 
246 	    if ((remainder = strchr(tcp_port, delimiter)))
247 		*remainder = 0;
248 	}
249     }
250 
251     if (!remainder) {
252 	Debug((DEBUG_COMMAND, "- %s: parse error\n", __func__));
253 	return -1;
254     }
255 
256     proto = atoi(net_prt);
257 
258     af = rfc2428_2_af(proto);
259     if (af < 0) {
260 	Debug((DEBUG_COMMAND, "- %s: unknown protocol\n", __func__));
261 	return -2;
262     }
263 
264     if (!tcp_port || su_pton_p(sa, net_addr, atoi(tcp_port)) || af != sa->sa.sa_family) {
265 	Debug((DEBUG_COMMAND, "- %s:  error\n", __func__));
266 	return -1;
267     }
268 
269     Debug((DEBUG_COMMAND, "- %s: af = %d\n", __func__, proto));
270     return sa->sa.sa_family;
271 }
272 
rfc959_eval(sockaddr_union * sa,char * s)273 int rfc959_eval(sockaddr_union * sa, char *s)
274 {
275     u_char arr[6];
276     int length = 0;
277 
278     DebugIn(DEBUG_COMMAND);
279 
280     if (!s) {
281 	Debug((DEBUG_COMMAND, "- %s: arg == NULL\n", __func__));
282 	return -1;
283     }
284 
285     memset(arr, 0, (size_t) 6);
286 
287     while (*s && isspace((int) *s))
288 	s++;
289 
290     for (; *s && !isspace((int) *s) && length < 6; s++)
291 	if (isdigit((int) *s)) {
292 	    arr[length] *= 10;
293 	    arr[length] += (u_char) * s - '0';
294 	} else if (*s == ',')
295 	    length++;
296 	else {
297 	    Debug((DEBUG_COMMAND, "- %s: invalid char\n", __func__));
298 	    return -1;
299 	}
300 
301     if (length != 5) {
302 	Debug((DEBUG_COMMAND, "- %s: consistency check failed\n", __func__));
303 	return -1;
304     }
305 
306     memset(sa, 0, sizeof(sockaddr_union));
307     sa->sa.sa_family = AF_INET;
308     memcpy(&sa->sin.sin_addr, arr, (size_t) 4);
309     memcpy(&sa->sin.sin_port, arr + 4, (size_t) 2);
310 
311     Debug((DEBUG_COMMAND, "- %s: af = AF_INET\n", __func__));
312     return AF_INET;
313 }
314 
rfc959_str(sockaddr_union * sa,char * res,size_t reslen)315 char *rfc959_str(sockaddr_union * sa, char *res, size_t reslen)
316 {
317     char *s = res;
318     int al = 4, pl = 2;
319     u_char *a = NULL, *p = NULL;
320     switch (sa->sa.sa_family) {
321 #ifdef AF_INET
322     case AF_INET:
323 	a = (u_char *) & sa->sin.sin_addr;
324 	p = (u_char *) & sa->sin.sin_port;
325 	break;
326 #endif				/* AF_INET */
327 #ifdef AF_INET6
328     case AF_INET6:
329 	a = (u_char *) & sa->sin6.sin6_addr + 12;
330 	p = (u_char *) & sa->sin6.sin6_port;
331 	break;
332 #endif				/* AF_INET6 */
333     default:
334 	return "";
335     }
336 
337     for (; al; a++, al--) {
338 	if (al != 4)
339 	    *s++ = ',';
340 	s += snprintf(s, (size_t) (res + reslen - s), "%u", (u_int) * a);
341     }
342 
343     for (; pl; p++, pl--)
344 	s += snprintf(s, (size_t) (res + reslen - s), ",%u", (u_int) * p);
345 
346     return res;
347 }
348 
rfc2428_str(sockaddr_union * sa,char * res,size_t reslen)349 char *rfc2428_str(sockaddr_union * sa, char *res, size_t reslen)
350 {
351     char buf[INET6_ADDRSTRLEN];
352     char *s = res;
353     char delimiter = '|';
354     u_short p;
355 
356     *s++ = delimiter;
357 
358     switch (sa->sa.sa_family) {
359 #ifdef AF_INET
360     case AF_INET:
361 	*s++ = RFC2428_AF_IP + '0';
362 	p = sa->sin.sin_port;
363 	break;
364 #endif
365 #ifdef AF_INET6
366     case AF_INET6:
367 	*s++ = RFC2428_AF_IP6 + '0';
368 	p = sa->sin6.sin6_port;
369 	break;
370 #endif
371     default:
372 	return "(NULL)";
373     }
374 
375     snprintf(s, (size_t) (res + reslen - s - 1), "%c%s%c%d%c", delimiter, su_ntop(sa, buf, (socklen_t) sizeof(buf)), delimiter, ntohs(p), delimiter);
376 
377     return res;
378 }
379