1 /* source: sysutils.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4 
5 /* translate socket addresses into human readable form */
6 
7 #include "config.h"
8 #include "xioconfig.h"
9 
10 #include "sysincludes.h"
11 
12 #include "compat.h"	/* socklen_t */
13 #include "mytypes.h"
14 #include "error.h"
15 #include "sycls.h"
16 #include "utils.h"
17 #include "sysutils.h"
18 
19 /* Substitute for Write():
20    Try to write all bytes before returning; this handles EINTR,
21    EAGAIN/EWOULDBLOCK, and partial write situations. The drawback is that this
22    function might block even with O_NONBLOCK option.
23    Returns <0 on unhandled error, errno valid
24    Will only return <0 or bytes
25 */
writefull(int fd,const void * buff,size_t bytes)26 ssize_t writefull(int fd, const void *buff, size_t bytes) {
27    size_t writt = 0;
28    ssize_t chk;
29    while (1) {
30       chk = Write(fd, (const char *)buff + writt, bytes - writt);
31       if (chk < 0) {
32 	 switch (errno) {
33 	 case EINTR:
34 	 case EAGAIN:
35 #if EAGAIN != EWOULDBLOCK
36 	 case EWOULDBLOCK:
37 #endif
38 	    Warn4("write(%d, %p, "F_Zu"): %s", fd, (const char *)buff+writt, bytes-writt, strerror(errno));
39 	    Sleep(1); continue;
40 	 default: return -1;
41 	 }
42       } else if (writt+chk < bytes) {
43 	 Warn4("write(%d, %p, "F_Zu"): only wrote "F_Zu" bytes, trying to continue ",
44 	       fd, (const char *)buff+writt, bytes-writt, chk);
45 	 writt += chk;
46       } else {
47 	 writt = bytes;
48 	 break;
49       }
50    }
51    return writt;
52 }
53 
54 #if WITH_UNIX
socket_un_init(struct sockaddr_un * sa)55 void socket_un_init(struct sockaddr_un *sa) {
56 #if HAVE_STRUCT_SOCKADDR_SALEN
57    sa->sun_len         = sizeof(struct sockaddr_un);
58 #endif
59    sa->sun_family      = AF_UNIX;
60    memset(sa->sun_path, '\0', sizeof(sa->sun_path));
61 }
62 #endif /* WITH_UNIX */
63 
64 #if WITH_IP4
socket_in_init(struct sockaddr_in * sa)65 void socket_in_init(struct sockaddr_in *sa) {
66 #if HAVE_STRUCT_SOCKADDR_SALEN
67    sa->sin_len         = sizeof(struct sockaddr_in);
68 #endif
69    sa->sin_family      = AF_INET;
70    sa->sin_port        = 0;
71    sa->sin_addr.s_addr = 0;
72    sa->sin_zero[0]     = 0;
73    sa->sin_zero[1]     = 0;
74    sa->sin_zero[2]     = 0;
75    sa->sin_zero[3]     = 0;
76    sa->sin_zero[4]     = 0;
77    sa->sin_zero[5]     = 0;
78    sa->sin_zero[6]     = 0;
79    sa->sin_zero[7]     = 0;
80 }
81 #endif /* WITH_IP4 */
82 
83 #if WITH_IP6
socket_in6_init(struct sockaddr_in6 * sa)84 void socket_in6_init(struct sockaddr_in6 *sa) {
85 #if HAVE_STRUCT_SOCKADDR_SALEN
86    sa->sin6_len        = sizeof(struct sockaddr_in6);
87 #endif
88    sa->sin6_family     = AF_INET6;
89    sa->sin6_port       = 0;
90    sa->sin6_flowinfo   = 0;
91 #if HAVE_IP6_SOCKADDR==0
92    sa->sin6_addr.s6_addr[0] = 0;
93    sa->sin6_addr.s6_addr[1] = 0;
94    sa->sin6_addr.s6_addr[2] = 0;
95    sa->sin6_addr.s6_addr[3] = 0;
96    sa->sin6_addr.s6_addr[4] = 0;
97    sa->sin6_addr.s6_addr[5] = 0;
98    sa->sin6_addr.s6_addr[6] = 0;
99    sa->sin6_addr.s6_addr[7] = 0;
100    sa->sin6_addr.s6_addr[8] = 0;
101    sa->sin6_addr.s6_addr[9] = 0;
102    sa->sin6_addr.s6_addr[10] = 0;
103    sa->sin6_addr.s6_addr[11] = 0;
104    sa->sin6_addr.s6_addr[12] = 0;
105    sa->sin6_addr.s6_addr[13] = 0;
106    sa->sin6_addr.s6_addr[14] = 0;
107    sa->sin6_addr.s6_addr[15] = 0;
108 #elif HAVE_IP6_SOCKADDR==1
109    sa->sin6_addr.u6_addr.u6_addr32[0] = 0;
110    sa->sin6_addr.u6_addr.u6_addr32[1] = 0;
111    sa->sin6_addr.u6_addr.u6_addr32[2] = 0;
112    sa->sin6_addr.u6_addr.u6_addr32[3] = 0;
113 #elif HAVE_IP6_SOCKADDR==2
114    sa->sin6_addr.u6_addr32[0] = 0;
115    sa->sin6_addr.u6_addr32[1] = 0;
116    sa->sin6_addr.u6_addr32[2] = 0;
117    sa->sin6_addr.u6_addr32[3] = 0;
118 #elif HAVE_IP6_SOCKADDR==3
119    sa->sin6_addr.in6_u.u6_addr32[0] = 0;
120    sa->sin6_addr.in6_u.u6_addr32[1] = 0;
121    sa->sin6_addr.in6_u.u6_addr32[2] = 0;
122    sa->sin6_addr.in6_u.u6_addr32[3] = 0;
123 #elif HAVE_IP6_SOCKADDR==4
124    sa->sin6_addr._S6_un._S6_u32[0] = 0;
125    sa->sin6_addr._S6_un._S6_u32[1] = 0;
126    sa->sin6_addr._S6_un._S6_u32[2] = 0;
127    sa->sin6_addr._S6_un._S6_u32[3] = 0;
128 #elif HAVE_IP6_SOCKADDR==5
129    sa->sin6_addr.__u6_addr.__u6_addr32[0] = 0;
130    sa->sin6_addr.__u6_addr.__u6_addr32[1] = 0;
131    sa->sin6_addr.__u6_addr.__u6_addr32[2] = 0;
132    sa->sin6_addr.__u6_addr.__u6_addr32[3] = 0;
133 #endif
134 }
135 #endif /* WITH_IP6 */
136 
137 
138 #if _WITH_SOCKET
139 /* initializes the socket address of the specified address family. Returns the
140    length of the specific socket address, or 0 on error. */
socket_init(int af,union sockaddr_union * sa)141 socklen_t socket_init(int af, union sockaddr_union *sa) {
142    switch (af) {
143    case AF_UNSPEC: memset(sa, 0, sizeof(*sa)); return sizeof(*sa);
144 #if WITH_UNIX
145    case AF_UNIX:   socket_un_init(&sa->un);   return sizeof(sa->un);
146 #endif
147 #if WITH_IP4
148    case AF_INET:   socket_in_init(&sa->ip4);  return sizeof(sa->ip4);
149 #endif
150 #if WITH_IP6
151    case AF_INET6:  socket_in6_init(&sa->ip6); return sizeof(sa->ip6);
152 #endif
153    default: Info1("socket_init(): unknown address family %d", af);
154       memset(sa, 0, sizeof(union sockaddr_union));
155       sa->soa.sa_family = af;
156       return 0;
157    }
158 }
159 #endif /* _WITH_SOCKET */
160 
161 #if WITH_UNIX
162 #define XIOUNIXSOCKOVERHEAD (sizeof(struct sockaddr_un)-sizeof(((struct sockaddr_un*)0)->sun_path))
163 #endif
164 
165 #if _WITH_SOCKET
166 /* writes a textual human readable representation of the sockaddr contents to buff and returns a pointer to buff
167    writes at most blen bytes to buff including the terminating \0 byte
168  */
sockaddr_info(const struct sockaddr * sa,socklen_t salen,char * buff,size_t blen)169 char *sockaddr_info(const struct sockaddr *sa, socklen_t salen, char *buff, size_t blen) {
170    union sockaddr_union *sau = (union sockaddr_union *)sa;
171    char *lbuff = buff;
172    char *cp = lbuff;
173    int n;
174 
175 #if HAVE_STRUCT_SOCKADDR_SALEN
176    n = xio_snprintf(cp, blen, "LEN=%d ", sau->soa.sa_len);
177    if (n < 0 || n >= blen) {
178       Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
179       *buff = '\0';
180       return buff;
181    }
182    cp += n,  blen -= n;
183 #endif
184    n = xio_snprintf(cp, blen, "AF=%d ", sau->soa.sa_family);
185    if (n < 0 || n >= blen) {
186       Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
187       *buff = '\0';
188       return buff;
189    }
190    cp += n,  blen -= n;
191 
192    switch (sau->soa.sa_family) {
193 #if WITH_UNIX
194    case 0:
195    case AF_UNIX: sockaddr_unix_info(&sau->un, salen, cp+1, blen-1);
196       cp[0] = '"';
197       strncat(cp+1, "\"", 1);
198       break;
199 #endif
200 #if WITH_IP4
201    case AF_INET: sockaddr_inet4_info(&sau->ip4, cp, blen);
202       break;
203 #endif
204 #if WITH_IP6
205    case AF_INET6: sockaddr_inet6_info(&sau->ip6, cp, blen);
206       break;
207 #endif
208 #if WITH_VSOCK
209    case AF_VSOCK: sockaddr_vm_info(&sau->vm, cp, blen);
210       break;
211 #endif
212    default:
213       n = xio_snprintf(cp, blen, "AF=%d ", sa->sa_family);
214       if (n < 0 || n >= blen) {
215 	 Warn1("sockaddr_info(): buffer too short ("F_Zu")", blen);
216 	 *buff = '\0';
217 	 return buff;
218       }
219       cp += n,  blen -= n;
220       n = xio_snprintf(cp, blen,
221 		    "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
222 		    ((unsigned char *)sau->soa.sa_data)[0],
223 		    ((unsigned char *)sau->soa.sa_data)[1],
224 		    ((unsigned char *)sau->soa.sa_data)[2],
225 		    ((unsigned char *)sau->soa.sa_data)[3],
226 		    ((unsigned char *)sau->soa.sa_data)[4],
227 		    ((unsigned char *)sau->soa.sa_data)[5],
228 		    ((unsigned char *)sau->soa.sa_data)[6],
229 		    ((unsigned char *)sau->soa.sa_data)[7],
230 		    ((unsigned char *)sau->soa.sa_data)[8],
231 		    ((unsigned char *)sau->soa.sa_data)[9],
232 		    ((unsigned char *)sau->soa.sa_data)[10],
233 		    ((unsigned char *)sau->soa.sa_data)[11],
234 		    ((unsigned char *)sau->soa.sa_data)[12],
235 		   ((unsigned char *)sau->soa.sa_data)[13]);
236       if (n < 0 || n >= blen) {
237 	 Warn("sockaddr_info(): buffer too short");
238 	 *buff = '\0';
239 	 return buff;
240       }
241    }
242    return lbuff;
243 }
244 #endif /* _WITH_SOCKET */
245 
246 
247 #if WITH_UNIX
sockaddr_unix_info(const struct sockaddr_un * sa,socklen_t salen,char * buff,size_t blen)248 char *sockaddr_unix_info(const struct sockaddr_un *sa, socklen_t salen, char *buff, size_t blen) {
249    char ubuff[5*UNIX_PATH_MAX+3];
250    char *nextc;
251 
252 #if WITH_ABSTRACT_UNIXSOCKET
253    if (salen > XIOUNIXSOCKOVERHEAD &&
254        sa->sun_path[0] == '\0') {
255       nextc =
256 	 sanitize_string(sa->sun_path, salen-XIOUNIXSOCKOVERHEAD,
257 			 ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
258    } else
259 #endif /* WITH_ABSTRACT_UNIXSOCKET */
260    {
261       if (salen <= XIOUNIXSOCKOVERHEAD) {
262 	 nextc = sanitize_string ("<anon>", MIN(UNIX_PATH_MAX, strlen("<anon>")),
263 				  ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
264       } else {
265 	 nextc = sanitize_string(sa->sun_path,
266 				 MIN(UNIX_PATH_MAX, strlen(sa->sun_path)),
267 				 ubuff, XIOSAN_DEFAULT_BACKSLASH_OCT_3);
268       }
269    }
270    *nextc = '\0';
271    buff[0] = '\0'; strncat(buff, ubuff, blen-1);
272    return buff;
273 }
274 #endif /* WITH_UNIX */
275 
276 #if WITH_IP4
277 /* addr in host byte order! */
inet4addr_info(uint32_t addr,char * buff,size_t blen)278 char *inet4addr_info(uint32_t addr, char *buff, size_t blen) {
279    if (xio_snprintf(buff, blen, "%u.%u.%u.%u",
280 		(unsigned int)(addr >> 24), (unsigned int)((addr >> 16) & 0xff),
281 		(unsigned int)((addr >> 8) & 0xff), (unsigned int)(addr & 0xff)) >= blen) {
282       Warn("inet4addr_info(): buffer too short");
283       buff[blen-1] = '\0';
284    }
285    return buff;
286 }
287 #endif /* WITH_IP4 */
288 
289 #if WITH_IP4
sockaddr_inet4_info(const struct sockaddr_in * sa,char * buff,size_t blen)290 char *sockaddr_inet4_info(const struct sockaddr_in *sa, char *buff, size_t blen) {
291    if (xio_snprintf(buff, blen, "%u.%u.%u.%u:%hu",
292 		((unsigned char *)&sa->sin_addr.s_addr)[0],
293 		((unsigned char *)&sa->sin_addr.s_addr)[1],
294 		((unsigned char *)&sa->sin_addr.s_addr)[2],
295 		((unsigned char *)&sa->sin_addr.s_addr)[3],
296 		htons(sa->sin_port)) >= blen) {
297       Warn("sockaddr_inet4_info(): buffer too short");
298       buff[blen-1] = '\0';
299    }
300    return buff;
301 }
302 #endif /* WITH_IP4 */
303 
304 #if WITH_VSOCK
sockaddr_vm_info(const struct sockaddr_vm * sa,char * buff,size_t blen)305 char *sockaddr_vm_info(const struct sockaddr_vm *sa, char *buff, size_t blen) {
306    if (xio_snprintf(buff, blen, "cid:%u port:%u", sa->svm_cid, sa->svm_port) >= blen) {
307       Warn("sockaddr_vm_info(): buffer too short");
308       buff[blen-1] = '\0';
309    }
310    return buff;
311 }
312 
sockaddr_vm_parse(struct sockaddr_vm * sa,const char * cid_str,const char * port_str)313 int sockaddr_vm_parse(struct sockaddr_vm *sa, const char *cid_str,
314                       const char *port_str)
315 {
316    char *garbage = NULL;
317    if (!cid_str) {
318       sa->svm_cid = VMADDR_CID_ANY;
319    } else {
320       sa->svm_cid = strtoul(cid_str, &garbage, 0);
321       if (*garbage != '\0') {
322          Error1("sockaddr_vm - garbage in cid: \"%s\"", garbage);
323          return -EINVAL;
324       }
325    }
326 
327    if (!port_str) {
328       sa->svm_port = VMADDR_PORT_ANY;
329    } else {
330       sa->svm_port = strtoul(port_str, &garbage, 0);
331       if (*garbage != '\0') {
332          Error1("sockaddr_vm - garbage in port: \"%s\"", garbage);
333          return -EINVAL;
334       }
335    }
336 
337    return 0;
338 }
339 #endif /* WITH_IP4 */
340 
341 #if !HAVE_INET_NTOP
342 /* http://www.opengroup.org/onlinepubs/000095399/functions/inet_ntop.html */
inet_ntop(int pf,const void * binaddr,char * addrtext,socklen_t textlen)343 const char *inet_ntop(int pf, const void *binaddr,
344 		      char *addrtext, socklen_t textlen) {
345    size_t retlen;
346    switch (pf) {
347    case PF_INET:
348       if ((retlen =
349 	   xio_snprintf(addrtext, textlen, "%u.%u.%u.%u",
350 		    ((unsigned char *)binaddr)[0],
351 		    ((unsigned char *)binaddr)[1],
352 		    ((unsigned char *)binaddr)[2],
353 		    ((unsigned char *)binaddr)[3]))
354 	  >= textlen) {
355 	 errno = ENOSPC; return NULL;
356       }
357       break;
358 #if WITH_IP6
359    case PF_INET6:
360       if ((retlen =
361 	   xio_snprintf(addrtext, textlen, "%x:%x:%x:%x:%x:%x:%x:%x",
362 		    ntohs(((uint16_t *)binaddr)[0]),
363 		    ntohs(((uint16_t *)binaddr)[1]),
364 		    ntohs(((uint16_t *)binaddr)[2]),
365 		    ntohs(((uint16_t *)binaddr)[3]),
366 		    ntohs(((uint16_t *)binaddr)[4]),
367 		    ntohs(((uint16_t *)binaddr)[5]),
368 		    ntohs(((uint16_t *)binaddr)[6]),
369 		    ntohs(((uint16_t *)binaddr)[7])
370 		    ))
371 	  >= textlen) {
372 	 errno = ENOSPC; return NULL;
373       }
374       break;
375 #endif /* WITH_IP6 */
376    default:
377       errno = EAFNOSUPPORT;
378       return NULL;
379    }
380    addrtext[retlen] = '\0';
381    return addrtext;
382 }
383 #endif /* !HAVE_INET_NTOP */
384 
385 #if WITH_IP6
386 /* convert the IP6 socket address to human readable form. buff should be at
387    least 50 chars long. output includes the port number */
sockaddr_inet6_info(const struct sockaddr_in6 * sa,char * buff,size_t blen)388 char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen) {
389    if (xio_snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:%hu",
390 #if HAVE_IP6_SOCKADDR==0
391 		(sa->sin6_addr.s6_addr[0]<<8)+
392 		sa->sin6_addr.s6_addr[1],
393 		(sa->sin6_addr.s6_addr[2]<<8)+
394 		sa->sin6_addr.s6_addr[3],
395 		(sa->sin6_addr.s6_addr[4]<<8)+
396 		sa->sin6_addr.s6_addr[5],
397 		(sa->sin6_addr.s6_addr[6]<<8)+
398 		sa->sin6_addr.s6_addr[7],
399 		(sa->sin6_addr.s6_addr[8]<<8)+
400 		sa->sin6_addr.s6_addr[9],
401 		(sa->sin6_addr.s6_addr[10]<<8)+
402 		sa->sin6_addr.s6_addr[11],
403 		(sa->sin6_addr.s6_addr[12]<<8)+
404 		sa->sin6_addr.s6_addr[13],
405 		(sa->sin6_addr.s6_addr[14]<<8)+
406 		sa->sin6_addr.s6_addr[15],
407 #elif HAVE_IP6_SOCKADDR==1
408 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[0]),
409 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[1]),
410 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[2]),
411 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[3]),
412 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[4]),
413 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[5]),
414 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[6]),
415 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr.u6_addr16)[7]),
416 #elif HAVE_IP6_SOCKADDR==2
417 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[0]),
418 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[1]),
419 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[2]),
420 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[3]),
421 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[4]),
422 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[5]),
423 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[6]),
424 		ntohs(((unsigned short *)&sa->sin6_addr.u6_addr16)[7]),
425 #elif HAVE_IP6_SOCKADDR==3
426 		ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[0]),
427 		ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[1]),
428 		ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[2]),
429 		ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[3]),
430 		ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[4]),
431 		ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[5]),
432 		ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[6]),
433 		ntohs(((unsigned short *)&sa->sin6_addr.in6_u.u6_addr16)[7]),
434 #elif HAVE_IP6_SOCKADDR==4
435 		(sa->sin6_addr._S6_un._S6_u8[0]<<8)|(sa->sin6_addr._S6_un._S6_u8[1]&0xff),
436 		(sa->sin6_addr._S6_un._S6_u8[2]<<8)|(sa->sin6_addr._S6_un._S6_u8[3]&0xff),
437 		(sa->sin6_addr._S6_un._S6_u8[4]<<8)|(sa->sin6_addr._S6_un._S6_u8[5]&0xff),
438 		(sa->sin6_addr._S6_un._S6_u8[6]<<8)|(sa->sin6_addr._S6_un._S6_u8[7]&0xff),
439 		(sa->sin6_addr._S6_un._S6_u8[8]<<8)|(sa->sin6_addr._S6_un._S6_u8[9]&0xff),
440 		(sa->sin6_addr._S6_un._S6_u8[10]<<8)|(sa->sin6_addr._S6_un._S6_u8[11]&0xff),
441 		(sa->sin6_addr._S6_un._S6_u8[12]<<8)|(sa->sin6_addr._S6_un._S6_u8[13]&0xff),
442 		(sa->sin6_addr._S6_un._S6_u8[14]<<8)|(sa->sin6_addr._S6_un._S6_u8[15]&0xff),
443 #elif HAVE_IP6_SOCKADDR==5
444 		ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[0]),
445 		ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[1]),
446 		ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[2]),
447 		ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[3]),
448 		ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[4]),
449 		ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[5]),
450 		ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[6]),
451 		ntohs(((unsigned short *)&sa->sin6_addr.__u6_addr.__u6_addr16)[7]),
452 #endif
453 		ntohs(sa->sin6_port)) >= blen) {
454       Warn("sockaddr_inet6_info(): buffer too short");
455    }
456    return buff;
457 }
458 #endif /* WITH_IP6 */
459 
460 #if HAVE_GETGROUPLIST || (defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT))
461 /* fills the list with the supplementary group ids of user.
462    caller passes size of list in ngroups, function returns number of groups in
463    ngroups.
464    function returns 0 if 0 or more groups were found, or 1 if the list is too
465    short. */
getusergroups(const char * user,gid_t * list,int * ngroups)466 int getusergroups(const char *user, gid_t *list, int *ngroups) {
467 #if HAVE_GETGROUPLIST
468    /* we prefer getgrouplist because it may be much faster with many groups, but it is not standard */
469    gid_t grp, twogrps[2];
470    int two = 2;
471    /* getgrouplist requires to pass an extra group id, typically the users primary group, that is then added to the supplementary group list. We don't want such an additional group in the result, but there is not "unspecified" gid value available. Thus we try to find an abitrary supplementary group id that we then pass in a second call to getgrouplist. */
472    grp = 0;
473    Getgrouplist(user, grp, twogrps, &two);
474    if (two == 1) {
475       /* either user has just this supp group, or none; we try another id */
476       grp = 1; two = 2;
477       Getgrouplist(user, grp, twogrps, &two);
478       if (two == 1) {
479 	 /* user has no supp group */
480 	 *ngroups = 0;
481 	 return 0;
482       }
483       /* user has just the first tried group */
484       *ngroups = 1; list[0] = grp;
485       return 0;
486    }
487    /* find the first supp group that is not our grp, and use its id */
488    if (twogrps[0] == grp) {
489       grp = twogrps[1];
490    } else {
491       grp = twogrps[0];
492    }
493    if (Getgrouplist(user, grp, list, ngroups) < 0) {
494       return 1;
495    }
496    return 0;
497 
498 #elif defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT)
499    /* this is standard (POSIX) but may be slow */
500 
501    struct group *grp;
502    int i = 0;
503 
504    setgrent();
505    while (grp = getgrent()) {
506       char **gusr = grp->gr_mem;
507       while (*gusr) {
508 	 if (!strcmp(*gusr, user)) {
509 	    if (i == *ngroups)
510 	       return 1;
511 	    list[i++] = grp->gr_gid;
512 	    break;
513 	 }
514 	 ++gusr;
515       }
516    }
517    endgrent();
518    *ngroups = i;
519    return 0;
520 #endif /* HAVE_SETGRENT... */
521 }
522 #endif
523 
524 #if !HAVE_HSTRERROR
hstrerror(int err)525 const char *hstrerror(int err) {
526    static const char *h_messages[] = {
527       "success",
528       "authoritative answer not found",
529       "non-authoritative, host not found, or serverfail",
530       "Host name lookup failure",	/* "non recoverable error" */
531       "valid name, no data record of requested type" };
532 
533    assert(HOST_NOT_FOUND==1);
534    assert(TRY_AGAIN==2);
535    assert(NO_RECOVERY==3);
536    assert(NO_DATA==4);
537    if ((err < 0) || err > sizeof(h_messages)/sizeof(const char *)) {
538       return "";
539    }
540    return h_messages[err];
541 }
542 #endif /* !HAVE_HSTRERROR */
543 
544 
545 /* this function behaves like poll(). It tries to do so even when the poll()
546    system call is not available. */
547 /* note: glibc 5.4 does not know nfds_t */
xiopoll(struct pollfd fds[],unsigned long nfds,struct timeval * timeout)548 int xiopoll(struct pollfd fds[], unsigned long nfds, struct timeval *timeout) {
549    int i, n = 0;
550    int result = 0;
551 
552    while (true) { /* should be if (), but we want to break */
553       fd_set readfds;
554       fd_set writefds;
555       fd_set exceptfds;
556 
557       FD_ZERO(&readfds);  FD_ZERO(&writefds);  FD_ZERO(&exceptfds);
558       for (i = 0; i < nfds; ++i) {
559 	 fds[i].revents = 0;
560 	 if (fds[i].fd < 0)  { continue; }
561 	 if (fds[i].fd > FD_SETSIZE)  { break; /* use poll */ }
562 	 if (fds[i].events & POLLIN)  {
563 	    FD_SET(fds[i].fd, &readfds);  n = MAX(n, fds[i].fd); }
564 	 if (fds[i].events & POLLOUT) {
565 	    FD_SET(fds[i].fd, &writefds); n = MAX(n, fds[i].fd); }
566       }
567       if (i < nfds)  { break; /* use poll */ }
568 
569       result = Select(n+1, &readfds, &writefds, &exceptfds, timeout);
570       if (result < 0)  { return result; }
571       for (i = 0; i < nfds; ++i) {
572 	 if (fds[i].fd < 0)  { continue; }
573 	 if ((fds[i].events & POLLIN)  && FD_ISSET(fds[i].fd, &readfds))  {
574 	    fds[i].revents |= POLLIN;  ++result;
575 	 }
576 	 if ((fds[i].events & POLLOUT) && FD_ISSET(fds[i].fd, &writefds)) {
577 	    fds[i].revents |= POLLOUT; ++result;
578 	 }
579       }
580       return result;
581    }
582    {
583 #if HAVE_POLL
584       int ms = 0;
585       if (timeout == NULL) {
586 	 ms = -1;
587       } else {
588 	 ms = 1000*timeout->tv_sec + timeout->tv_usec/1000;
589       }
590       /*! timeout */
591       return Poll(fds, nfds, ms);
592 #else /* HAVE_POLL */
593       Error("poll() not available");
594       return -1;
595 #endif /* !HAVE_POLL */
596    }
597 }
598 
599 
600 #if WITH_TCP || WITH_UDP
601 /* returns port in network byte order;
602    ipproto==IPPROTO_UDP resolves as UDP service, every other value resolves as
603    TCP */
parseport(const char * portname,int ipproto)604 int parseport(const char *portname, int ipproto) {
605    struct servent *se;
606    char *extra;
607    int result;
608 
609    if (isdigit(portname[0]&0xff)) {
610       result = htons(strtoul(portname, &extra, 0));
611       if (*extra != '\0') {
612 	 Error3("parseport(\"%s\", %d): extra trailing data \"%s\"",
613 		portname, ipproto, extra);
614       }
615       return result;
616    }
617 
618    if ((se = getservbyname(portname, ipproto==IPPROTO_UDP?"udp":"tcp")) == NULL) {
619       Error2("cannot resolve service \"%s/%d\"", portname, ipproto);
620       return 0;
621    }
622 
623    return se->s_port;
624 }
625 #endif /* WITH_TCP || WITH_UDP */
626 
627 
628 #if WITH_IP4 || WITH_IP6 || WITH_INTERFACE
629 /* check the systems interfaces for ifname and return its index
630    or -1 if no interface with this name was found
631    The system calls require an arbitrary socket; the calling program may
632    provide one in anysock to avoid creation of a dummy socket. anysock must be
633    <0 if it does not specify a socket fd.
634  */
ifindexbyname(const char * ifname,int anysock)635 int ifindexbyname(const char *ifname, int anysock) {
636    /* Linux: man 7 netdevice */
637    /* FreeBSD: man 4 networking */
638    /* Solaris: man 7 if_tcp */
639 
640 #if defined(HAVE_STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX)
641    /* currently we support Linux, FreeBSD; not Solaris */
642 
643 #define IFBUFSIZ 32*sizeof(struct ifreq) /*1024*/
644    int s;
645    struct ifreq ifr;
646 
647    if (ifname[0] == '\0') {
648       return -1;
649    }
650    if (anysock >= 0) {
651       s = anysock;
652    } else  if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
653       Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno));
654       return -1;
655    }
656 
657    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);	/* ok */
658    if (Ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
659       Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}): %s",
660 	     s, ifr.ifr_name, strerror(errno));
661       Close(s);
662       return -1;
663    }
664    Close(s);
665 #if HAVE_STRUCT_IFREQ_IFR_INDEX
666    Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}) -> { %d }",
667          s, ifname, ifr.ifr_index);
668    return ifr.ifr_index;
669 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
670    Info3("ioctl(%d, SIOCGIFINDEX, {\"%s\"}) -> { %d }",
671          s, ifname, ifr.ifr_ifindex);
672    return ifr.ifr_ifindex;
673 #endif /* HAVE_STRUCT_IFREQ_IFR_IFINDEX */
674 
675 #else /* !defined(HAVE_ STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) */
676    return -1;
677 #endif /* !defined(HAVE_ STRUCT_IFREQ) && defined(SIOCGIFCONF) && defined(SIOCGIFINDEX) */
678 }
679 #endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
680 
681 
682 #if WITH_IP4 || WITH_IP6 || WITH_INTERFACE
683 /* like ifindexbyname(), but also allows the index number as input - in this
684    case it does not lookup the index.
685    writes the resulting index to *ifindex and returns 0,
686    or returns -1 on error */
ifindex(const char * ifname,unsigned int * ifindex,int anysock)687 int ifindex(const char *ifname, unsigned int *ifindex, int anysock) {
688    char *endptr;
689    long int val;
690 
691    if (ifname[0] == '\0') {
692       return -1;
693    }
694    val = strtol(ifname, &endptr, 0);
695    if (endptr[0] == '\0') {
696       *ifindex = val;
697       return 0;
698    }
699 
700    if ((val = ifindexbyname(ifname, anysock)) < 0) {
701       return -1;
702    }
703    *ifindex = val;
704    return 0;
705 }
706 #endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
707 
708 
_xiosetenv(const char * envname,const char * value,int overwrite,const char * sep)709 int _xiosetenv(const char *envname, const char *value, int overwrite, const char *sep) {
710    char *oldval;
711    char *newval;
712    if (overwrite >= 2 && (oldval = getenv(envname)) != NULL) {
713       size_t newlen = strlen(oldval)+strlen(sep)+strlen(value)+1;
714       if ((newval = Malloc(newlen+1)) == NULL) {
715 	 return -1;
716       }
717       snprintf(newval, newlen+1, "%s%s%s", oldval, sep, value);
718    } else {
719       newval = (char *)value;
720    }
721    if (Setenv(envname, newval, overwrite) < 0) {
722       Warn3("setenv(\"%s\", \"%s\", 1): %s",
723 	    envname, value, strerror(errno));
724 #if HAVE_UNSETENV
725       Unsetenv(envname);      /* dont want to have a wrong value */
726 #endif
727       return -1;
728    }
729    return 0;
730 }
731 
732 /* constructs an environment variable whose name is built from socats uppercase
733    program name, and underscore and varname;
734    if the variable of this name already exists arg overwrite determines:
735    0: keep old value
736    1: overwrite with new value
737    2: append to old value, separated by *sep
738    returns 0 on success or <0 if an error occurred. */
xiosetenv(const char * varname,const char * value,int overwrite,const char * sep)739 int xiosetenv(const char *varname, const char *value, int overwrite, const char *sep) {
740 #  define XIO_ENVNAMELEN 256
741    const char *progname;
742    char envname[XIO_ENVNAMELEN];
743    size_t i, l;
744 
745    progname = diag_get_string('p');
746    envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1);
747    l = strlen(envname);
748    for (i = 0; i < l; ++i)  envname[i] = toupper(envname[i]);
749    strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
750    l += 1;
751    strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
752    return _xiosetenv(envname, value, overwrite, sep);
753 #  undef XIO_ENVNAMELEN
754 }
755 
xiosetenv2(const char * varname,const char * varname2,const char * value,int overwrite,const char * sep)756 int xiosetenv2(const char *varname, const char *varname2, const char *value,
757 	       int overwrite, const char *sep) {
758 #  define XIO_ENVNAMELEN 256
759    const char *progname;
760    char envname[XIO_ENVNAMELEN];
761    size_t i, l;
762 
763    progname = diag_get_string('p');
764    envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1);
765    l = strlen(progname);
766    strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
767    l += 1;
768    strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
769    l += strlen(envname+l);
770    strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
771    l += 1;
772    strncat(envname+l, varname2, XIO_ENVNAMELEN-l-1);
773    l += strlen(envname+l);
774    for (i = 0; i < l; ++i)  envname[i] = toupper(envname[i]);
775    return _xiosetenv(envname, value, overwrite, sep);
776 #  undef XIO_ENVNAMELEN
777 }
778 
xiosetenv3(const char * varname,const char * varname2,const char * varname3,const char * value,int overwrite,const char * sep)779 int xiosetenv3(const char *varname, const char *varname2, const char *varname3,
780 	       const char *value,
781 	       int overwrite, const char *sep) {
782 #  define XIO_ENVNAMELEN 256
783    const char *progname;
784    char envname[XIO_ENVNAMELEN];
785    size_t i, l;
786 
787    progname = diag_get_string('p');
788    envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1);
789    l = strlen(progname);
790    strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
791    l += 1;
792    strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
793    l += strlen(envname+l);
794    strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
795    l += 1;
796    strncat(envname+l, varname2, XIO_ENVNAMELEN-l-1);
797    l += strlen(envname+l);
798    strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
799    l += 1;
800    strncat(envname+l, varname3, XIO_ENVNAMELEN-l-1);
801    l += strlen(envname+l);
802    for (i = 0; i < l; ++i)  envname[i] = toupper(envname[i]);
803    return _xiosetenv(envname, value, overwrite, sep);
804 #  undef XIO_ENVNAMELEN
805 }
806 
807 
808 /* like xiosetenv(), but uses an unsigned long value */
xiosetenvulong(const char * varname,unsigned long value,int overwrite)809 int xiosetenvulong(const char *varname, unsigned long value, int overwrite) {
810 #  define XIO_LONGLEN 21	/* should suffice for 64bit longs with \0 */
811    char envbuff[XIO_LONGLEN];
812 
813    snprintf(envbuff, XIO_LONGLEN, "%lu", value);
814    return xiosetenv(varname, envbuff, overwrite, NULL);
815 #  undef XIO_LONGLEN
816 }
817 
818 /* like xiosetenv(), but uses an unsigned short value */
xiosetenvushort(const char * varname,unsigned short value,int overwrite)819 int xiosetenvushort(const char *varname, unsigned short value, int overwrite) {
820 #  define XIO_SHORTLEN 11      /* should suffice for 32bit shorts with \0 */
821    char envbuff[XIO_SHORTLEN];
822 
823    snprintf(envbuff, XIO_SHORTLEN, "%hu", value);
824    return xiosetenv(varname, envbuff, overwrite, NULL);
825 #  undef XIO_SHORTLEN
826 }
827