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