1 /* IPSec VPN client compatible with Cisco equipment.
2     Copyright (C) 2007      Maurice Massar
3     Copyright (C) 2007      Paolo Zarpellon <paolo.zarpellon@gmail.com> (Cygwin support)
4 
5     based on VTun - Virtual Tunnel over TCP/IP network.
6     Copyright (C) 1998-2000  Maxim Krasnyansky <max_mk@yahoo.com>
7     VTun has been derived from VPPP package by Maxim Krasnyansky.
8 
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18  */
19 
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <syslog.h>
26 #include <sys/ioctl.h>
27 #include <errno.h>
28 
29 #include <sys/socket.h>
30 #include <net/if.h>
31 
32 #ifdef __sun__
33 #include <ctype.h>
34 #include <sys/time.h>
35 #include <sys/wait.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <signal.h>
40 #include <stropts.h>
41 #include <netinet/in.h>
42 #include <netinet/in_systm.h>
43 #include <netinet/ip.h>
44 #include <netinet/tcp.h>
45 #endif
46 
47 #if defined(__CYGWIN__)
48 #include <io.h>
49 #include <w32api/windef.h>
50 #include <w32api/winbase.h>
51 #include <w32api/winnt.h>
52 #include <w32api/winioctl.h>
53 #include <w32api/iphlpapi.h>
54 #include <w32api/iptypes.h>
55 #include <w32api/winreg.h>
56 #include <sys/cygwin.h>
57 #endif
58 
59 #if defined(__DragonFly__)
60 #include <net/tun/if_tun.h>
61 #elif defined(__linux__)
62 #include <linux/if_tun.h>
63 #elif defined(__APPLE__)
64 /* no header for tun */
65 #elif defined(__CYGWIN__)
66 #include "tap-win32.h"
67 #else
68 #include <net/if_tun.h>
69 #endif
70 
71 #include "sysdep.h"
72 
73 #if !defined(HAVE_VASPRINTF) || !defined(HAVE_ASPRINTF) || !defined(HAVE_ERROR)
74 #include <stdarg.h>
75 #endif
76 
77 #if defined(__sun__)
78 extern char **environ;
79 static int ip_fd = -1, muxid;
80 #endif
81 
82 #if defined(__CYGWIN__)
83 /*
84  * Overlapped structures for asynchronous read and write
85  */
86 static OVERLAPPED overlap_read, overlap_write;
87 
88 typedef enum {
89 	SEARCH_IF_GUID_FROM_NAME,
90 	SEARCH_IF_NAME_FROM_GUID
91 } search_if_en;
92 #endif
93 
94 #ifdef TUNSIFPID
tun_claim(int fd)95 void tun_claim(int fd)
96 {
97 
98 	ioctl(fd, TUNSIFPID, 0);
99 }
100 #else
101 /* Nop; no protocol for doing this */
tun_claim(int fd)102 void tun_claim(int fd)
103 {
104 
105 }
106 #endif
107 
108 /*
109  * Allocate TUN/TAP device, returns opened fd.
110  * Stores dev name in the first arg(must be large enough).
111  */
112 #if defined(__sun__)
tun_open(char * dev,enum if_mode_enum mode)113 int tun_open(char *dev, enum if_mode_enum mode)
114 {
115 	int tun_fd, if_fd, ppa = -1;
116 	struct ifreq ifr;
117 	char *ptr;
118 
119 	if (*dev) {
120 		ptr = dev;
121 		while (*ptr && !isdigit((int)*ptr))
122 			ptr++;
123 		ppa = atoi(ptr);
124 	}
125 
126 	if ((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) {
127 		syslog(LOG_ERR, "Can't open /dev/ip");
128 		return -1;
129 	}
130 
131 	if ((tun_fd = open(((mode == IF_MODE_TUN) ? "/dev/tun" : "/dev/tap"), O_RDWR, 0)) < 0) {
132 		syslog(LOG_ERR, "Can't open /dev/tun");
133 		return -1;
134 	}
135 
136 	/* Assign a new PPA and get its unit number. */
137 	if ((ppa = ioctl(tun_fd, TUNNEWPPA, ppa)) < 0) {
138 		syslog(LOG_ERR, "Can't assign new interface");
139 		return -1;
140 	}
141 
142 	if ((if_fd = open(((mode == IF_MODE_TUN) ? "/dev/tun" : "/dev/tap"), O_RDWR, 0)) < 0) {
143 		syslog(LOG_ERR, "Can't open /dev/tun (2)");
144 		return -1;
145 	}
146 	if (ioctl(if_fd, I_PUSH, "ip") < 0) {
147 		syslog(LOG_ERR, "Can't push IP module");
148 		return -1;
149 	}
150 
151 	/* Assign ppa according to the unit number returned by tun device */
152 	if (ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0 && errno != EEXIST) {
153 		syslog(LOG_ERR, "Can't set PPA %d", ppa);
154 		return -1;
155 	}
156 	if ((muxid = ioctl(ip_fd, I_PLINK, if_fd)) < 0) {
157 		syslog(LOG_ERR, "Can't link TUN device to IP");
158 		return -1;
159 	}
160 	close(if_fd);
161 
162 	snprintf(dev, IFNAMSIZ, "%s%d", ((mode == IF_MODE_TUN) ? "tun" : "tap"), ppa);
163 
164 	memset(&ifr, 0, sizeof(ifr));
165 	strcpy(ifr.ifr_name, dev);
166 	ifr.ifr_ip_muxid = muxid;
167 
168 	if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
169 		ioctl(ip_fd, I_PUNLINK, muxid);
170 		syslog(LOG_ERR, "Can't set multiplexor id");
171 		return -1;
172 	}
173 
174 	return tun_fd;
175 }
176 #elif defined(__CYGWIN__)
177 /*
178  * Get interface guid/name from registry
179  */
search_if(char * value,char * key,search_if_en type)180 static char *search_if(char *value, char *key, search_if_en type)
181 {
182 	int i = 0;
183 	LONG status;
184 	DWORD len;
185 	HKEY net_conn_key;
186 	BOOL found = FALSE;
187 	char guid[256];
188 	char ifname[256];
189 	char conn_string[512];
190 	HKEY conn_key;
191 	DWORD value_type;
192 
193 	if (!value || !key) {
194 		return NULL;
195 	}
196 
197 	status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
198 		NETWORK_CONNECTIONS_KEY,
199 		0,
200 		KEY_READ,
201 		&net_conn_key);
202 
203 	if (status != ERROR_SUCCESS) {
204 		printf("Error opening registry key: %s\n", NETWORK_CONNECTIONS_KEY);
205 		return NULL;
206 	}
207 
208 	while (!found) {
209 		len = sizeof(guid);
210 		status = RegEnumKeyEx(net_conn_key, i++, guid, &len,
211 			NULL, NULL, NULL, NULL);
212 		if (status == ERROR_NO_MORE_ITEMS) {
213 			break;
214 		} else if (status != ERROR_SUCCESS) {
215 			continue;
216 		}
217 		snprintf(conn_string, sizeof(conn_string),
218 			"%s\\%s\\Connection",
219 			NETWORK_CONNECTIONS_KEY, guid);
220 		status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
221 			conn_string,
222 			0,
223 			KEY_READ,
224 			&conn_key);
225 		if (status != ERROR_SUCCESS) {
226 			continue;
227 		}
228 		len = sizeof(ifname);
229 		status = RegQueryValueEx(conn_key, "Name", NULL,
230 			&value_type, ifname, &len);
231 		if (status != ERROR_SUCCESS || value_type != REG_SZ) {
232 			RegCloseKey(conn_key);
233 			continue;
234 		}
235 
236 		switch (type) {
237 		case SEARCH_IF_GUID_FROM_NAME:
238 			if (!strcmp(key, ifname)) {
239 				strcpy(value, guid);
240 				found = TRUE;
241 			}
242 			break;
243 		case SEARCH_IF_NAME_FROM_GUID:
244 			if (!strcmp(key, guid)) {
245 				strcpy(value, ifname);
246 				found = TRUE;
247 			}
248 			break;
249 		default:
250 			break;
251 		}
252 		RegCloseKey(conn_key);
253 	}
254 	RegCloseKey(net_conn_key);
255 
256 	if (found) {
257 		return value;
258 	}
259 
260 	return NULL;
261 }
262 
263 /*
264  * Open the TUN/TAP device with the provided guid
265  */
open_tun_device(char * guid,char * dev,enum if_mode_enum mode)266 static int open_tun_device (char *guid, char *dev, enum if_mode_enum mode)
267 {
268 	HANDLE handle;
269 	ULONG len, status, info[3];
270 	char device_path[512];
271 
272 	printf("Device: %s\n", dev);
273 
274 	if (mode == IF_MODE_TUN) {
275 		printf("TUN mode is not supported\n");
276 		return -1;
277 	}
278 
279 	/*
280 	 * Let's try to open Windows TAP-Win32 adapter
281 	 */
282 	snprintf(device_path, sizeof(device_path), "%s%s%s",
283 		USERMODEDEVICEDIR, guid, TAPSUFFIX);
284 
285 	handle = CreateFile(device_path,
286 		GENERIC_READ | GENERIC_WRITE,
287 		0, /* Don't let other processes share or open
288 		the resource until the handle's been closed */
289 		0,
290 		OPEN_EXISTING,
291 		FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
292 		0);
293 
294 	if (handle == INVALID_HANDLE_VALUE) {
295 		return -1;
296 	}
297 
298 	/*
299 	 * get driver version info
300 	 */
301 	memset(info, 0, sizeof(info));
302 	if (DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
303 		&info, sizeof(info),
304 		&info, sizeof(info), &len, NULL)) {
305 		printf("TAP-Win32 Driver Version %d.%d %s\n",
306 		(int) info[0],
307 		(int) info[1],
308 		(info[2] ? "(DEBUG)" : ""));
309 	}
310 
311 	/*
312 	 * Set driver media status to 'connected'
313 	 */
314 	status = TRUE;
315 	if (!DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
316 		&status, sizeof(status),
317 		&status, sizeof(status), &len, NULL)) {
318 		printf("WARNING: The TAP-Win32 driver rejected a "
319 		"TAP_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.\n");
320 	}
321 
322 	/*
323 	 * Initialize overlapped structures
324 	 */
325 	overlap_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
326 	overlap_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
327 	if (!overlap_read.hEvent || !overlap_write.hEvent) {
328 		return -1;
329 	}
330 
331 	/*
332 	 * Return fd
333 	 */
334 	return cygwin_attach_handle_to_fd(NULL, -1, handle, 1, GENERIC_READ | GENERIC_WRITE);
335 }
336 
337 /*
338  * Allocate TUN device, returns opened fd.
339  * Stores dev name in the first arg (must be large enough).
340  */
tun_open(char * dev,enum if_mode_enum mode)341 int tun_open (char *dev, enum if_mode_enum mode)
342 {
343 	int fd = -1;
344 	HKEY unit_key;
345 	char guid[256];
346 	char comp_id[256];
347 	char enum_name[256];
348 	char unit_string[512];
349 	BOOL found = FALSE;
350 	HKEY adapter_key;
351 	DWORD value_type;
352 	LONG status;
353 	DWORD len;
354 
355 	if (!dev) {
356 		return -1;
357 	}
358 
359 	/*
360 	 * Device name has been provided. Open such device.
361 	 */
362 	if (*dev != '\0') {
363 		if (!search_if(guid, dev, SEARCH_IF_GUID_FROM_NAME)) {
364 			return -1;
365 		}
366 		return open_tun_device(guid, dev, mode);
367 	}
368 
369 	/*
370 	 * Device name has non been specified. Look for one available!
371 	 */
372 	int i = 0;
373 	status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
374 		ADAPTER_KEY,
375 		0,
376 		KEY_READ,
377 		&adapter_key);
378 	if (status != ERROR_SUCCESS) {
379 		printf("Error opening registry key: %s", ADAPTER_KEY);
380 		return -1;
381 	}
382 
383 	while (!found) {
384 		len = sizeof(enum_name);
385 		status = RegEnumKeyEx(adapter_key, i++,
386 			enum_name, &len,
387 			NULL, NULL, NULL, NULL);
388 		if (status == ERROR_NO_MORE_ITEMS) {
389 			break;
390 		} else if (status != ERROR_SUCCESS) {
391 			continue;
392 		}
393 		snprintf(unit_string, sizeof(unit_string), "%s\\%s",
394 			ADAPTER_KEY, enum_name);
395 		status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
396 			unit_string,
397 			0,
398 			KEY_READ,
399 			&unit_key);
400 		if (status != ERROR_SUCCESS) {
401 			continue;
402 		}
403 		len = sizeof(comp_id);
404 		status = RegQueryValueEx(unit_key,
405 			"ComponentId", NULL,
406 			&value_type, comp_id, &len);
407 		if (status != ERROR_SUCCESS || value_type != REG_SZ) {
408 			RegCloseKey(unit_key);
409 			continue;
410 		}
411 		len = sizeof(guid);
412 		status = RegQueryValueEx(unit_key,
413 			"NetCfgInstanceId", NULL,
414 			&value_type, guid, &len);
415 		if (status != ERROR_SUCCESS || value_type != REG_SZ) {
416 			RegCloseKey(unit_key);
417 			continue;
418 		}
419 
420 		int j = 0;
421 		while (TAP_COMPONENT_ID[j]) {
422 			if (!strcmp(comp_id, TAP_COMPONENT_ID[j])) {
423 				break;
424 			}
425 			j++;
426 		}
427 		if (!TAP_COMPONENT_ID[j]) {
428 			RegCloseKey(unit_key);
429 			continue;
430 		}
431 
432 		/*
433 		 * Let's try to open this device
434 		 */
435 		search_if(dev, guid, SEARCH_IF_NAME_FROM_GUID);
436 		fd = open_tun_device(guid, dev, mode);
437 		if (fd != -1) {
438 			found = TRUE;
439 		}
440 
441 		RegCloseKey(unit_key);
442 	}
443 	RegCloseKey(adapter_key);
444 
445 	return fd;
446 }
447 #elif defined(IFF_TUN)
tun_open(char * dev,enum if_mode_enum mode)448 int tun_open(char *dev, enum if_mode_enum mode)
449 {
450 	struct ifreq ifr;
451 	int fd, err;
452 
453 	if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
454 		error(0, errno,
455 			"can't open /dev/net/tun, check that it is either device char 10 200 or (with DevFS) a symlink to ../misc/net/tun (not misc/net/tun)");
456 		return -1;
457 	}
458 
459 	memset(&ifr, 0, sizeof(ifr));
460 	ifr.ifr_flags = ((mode == IF_MODE_TUN) ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
461 	if (*dev)
462 		strncpy(ifr.ifr_name, dev, IFNAMSIZ);
463 
464 	if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
465 		close(fd);
466 		return err;
467 	}
468 	strcpy(dev, ifr.ifr_name);
469 	return fd;
470 }
471 #else
tun_open(char * dev,enum if_mode_enum mode)472 int tun_open(char *dev, enum if_mode_enum mode)
473 {
474 	char tunname[14];
475 	int i, fd;
476 
477 	if (*dev) {
478 		if (strncmp(dev, ((mode == IF_MODE_TUN) ? "tun" : "tap"), 3))
479 			error(1, 0,
480 				"error: arbitrary naming tunnel interface is not supported in this version\n");
481 		snprintf(tunname, sizeof(tunname), "/dev/%s", dev);
482 		return open(tunname, O_RDWR);
483 	}
484 
485 	for (i = 0; i < 255; i++) {
486 		snprintf(tunname, sizeof(tunname), "/dev/%s%d",
487 			((mode == IF_MODE_TUN) ? "tun" : "tap"), i);
488 		/* Open device */
489 		if ((fd = open(tunname, O_RDWR)) > 0) {
490 			snprintf(dev, IFNAMSIZ, "%s%d",
491 				((mode == IF_MODE_TUN) ? "tun" : "tap"), i);
492 			return fd;
493 		}
494 	}
495 	return -1;
496 }
497 #endif /* New driver support */
498 
499 /*
500  * Close TUN device.
501  */
502 #if defined(__sun__)
tun_close(int fd,char * dev)503 int tun_close(int fd, char *dev)
504 {
505 	struct ifreq ifr;
506 
507 	memset(&ifr, 0, sizeof(ifr));
508 	strcpy(ifr.ifr_name, dev);
509 	if (ioctl(ip_fd, SIOCGIFFLAGS, &ifr) < 0) {
510 		syslog(LOG_ERR, "Can't get iface flags");
511 		return 0;
512 	}
513 
514 	if (ioctl(ip_fd, I_PUNLINK, muxid) < 0) {
515 		syslog(LOG_ERR, "Can't unlink interface");
516 		return 0;
517 	}
518 
519 	close(ip_fd);
520 	ip_fd = -1;
521 	close(fd);
522 	return 0;
523 }
524 #elif defined(__CYGWIN__)
tun_close(int fd,char * dev)525 int tun_close(int fd, char *dev)
526 {
527 	dev = NULL; /* unused */
528 	return CloseHandle((HANDLE) get_osfhandle(fd));
529 }
530 #else
tun_close(int fd,char * dev)531 int tun_close(int fd, char *dev)
532 {
533 	dev = NULL; /*unused */
534 	return close(fd);
535 }
536 #endif
537 
538 
539 #if defined(__sun__)
tun_write(int fd,unsigned char * buf,int len)540 int tun_write(int fd, unsigned char *buf, int len)
541 {
542 	struct strbuf sbuf;
543 	sbuf.len = len;
544 	sbuf.buf = buf;
545 	return putmsg(fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1;
546 }
547 
tun_read(int fd,unsigned char * buf,int len)548 int tun_read(int fd, unsigned char *buf, int len)
549 {
550 	struct strbuf sbuf;
551 	int f = 0;
552 
553 	sbuf.maxlen = len;
554 	sbuf.buf = buf;
555 	return getmsg(fd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
556 }
557 #elif defined(__CYGWIN__)
tun_read(int fd,unsigned char * buf,int len)558 int tun_read(int fd, unsigned char *buf, int len)
559 {
560 	DWORD read_size;
561 
562 	ResetEvent(overlap_read.hEvent);
563 	if (ReadFile((HANDLE) get_osfhandle(fd), buf, len, &read_size, &overlap_read)) {
564 		return read_size;
565 	}
566 	switch (GetLastError()) {
567 	case ERROR_IO_PENDING:
568 		WaitForSingleObject(overlap_read.hEvent, INFINITE);
569 		GetOverlappedResult((HANDLE) get_osfhandle(fd), &overlap_read, &read_size, FALSE);
570 		return read_size;
571 		break;
572 	default:
573 		break;
574 	}
575 
576 	return -1;
577 }
578 
tun_write(int fd,unsigned char * buf,int len)579 int tun_write(int fd, unsigned char *buf, int len)
580 {
581 	DWORD write_size;
582 
583 	ResetEvent(overlap_write.hEvent);
584 	if (WriteFile((HANDLE) get_osfhandle(fd),
585 		buf,
586 		len,
587 		&write_size,
588 		&overlap_write)) {
589 		return write_size;
590 	}
591 	switch (GetLastError()) {
592 	case ERROR_IO_PENDING:
593 		WaitForSingleObject(overlap_write.hEvent, INFINITE);
594 		GetOverlappedResult((HANDLE) get_osfhandle(fd), &overlap_write,
595 			&write_size, FALSE);
596 		return write_size;
597 		break;
598 	default:
599 		break;
600 	}
601 
602 	return -1;
603 }
604 #elif defined(NEW_TUN)
605 #define MAX_MRU 2048
606 struct tun_data {
607 	union {
608 		uint32_t family;
609 		uint32_t timeout;
610 	} header;
611 	u_char data[MAX_MRU];
612 };
613 
614 /* Read/write frames from TUN device */
tun_write(int fd,unsigned char * buf,int len)615 int tun_write(int fd, unsigned char *buf, int len)
616 {
617 	char *data;
618 	struct tun_data tun;
619 
620 	if (len > (int)sizeof(tun.data))
621 		return -1;
622 
623 	memcpy(tun.data, buf, len);
624 	tun.header.family = htonl(AF_INET);
625 	len += (sizeof(tun) - sizeof(tun.data));
626 	data = (char *)&tun;
627 
628 	return write(fd, data, len) - (sizeof(tun) - sizeof(tun.data));
629 }
630 
tun_read(int fd,unsigned char * buf,int len)631 int tun_read(int fd, unsigned char *buf, int len)
632 {
633 	struct tun_data tun;
634 	char *data;
635 	size_t sz;
636 	int pack;
637 
638 	data = (char *)&tun;
639 	sz = sizeof(tun);
640 	pack = read(fd, data, sz);
641 	if (pack == -1)
642 		return -1;
643 
644 	pack -= sz - sizeof(tun.data);
645 	if (pack > len)
646 		pack = len; /* truncate paket */
647 
648 	memcpy(buf, tun.data, pack);
649 
650 	return pack;
651 }
652 
653 #else
654 
tun_write(int fd,unsigned char * buf,int len)655 int tun_write(int fd, unsigned char *buf, int len)
656 {
657 	return write(fd, buf, len);
658 }
659 
tun_read(int fd,unsigned char * buf,int len)660 int tun_read(int fd, unsigned char *buf, int len)
661 {
662 	return read(fd, buf, len);
663 }
664 
665 #endif
666 
667 /*
668  * Get HW addr
669  */
tun_get_hwaddr(int fd,char * dev,uint8_t * hwaddr)670 int tun_get_hwaddr(int fd, char *dev, uint8_t *hwaddr)
671 {
672 #if defined(__CYGWIN__)
673 	ULONG len;
674 
675 	dev = NULL; /* unused */
676 	if (!DeviceIoControl((HANDLE) get_osfhandle(fd), TAP_IOCTL_GET_MAC,
677 		hwaddr, ETH_ALEN, hwaddr, ETH_ALEN, &len, NULL)) {
678 		printf("Cannot get HW address\n");
679 		return -1;
680 	}
681 
682 	return 0;
683 #elif defined(SIOCGIFHWADDR)
684 	struct ifreq ifr;
685 
686 	/* Use a new socket fd! */
687 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
688 		return -1;
689 	}
690 
691 	memset(&ifr, 0, sizeof(struct ifreq));
692 	strncpy(ifr.ifr_name, dev, IFNAMSIZ);
693 
694 	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
695 		return -1;
696 	}
697 
698 	memcpy(hwaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
699 
700 	return 0;
701 #else
702 	/* todo: implement using SIOCGLIFADDR */
703 	fd = 0;
704 	dev = 0;
705 	hwaddr = 0;
706 	errno = ENOSYS;
707 	return -1;
708 #endif
709 }
710 
711 /***********************************************************************/
712 /* other support functions */
713 
714 #ifndef HAVE_VASPRINTF
vasprintf(char ** strp,const char * fmt,va_list ap)715 int vasprintf(char **strp, const char *fmt, va_list ap)
716 {
717 	int ret;
718 	char *strbuf;
719 
720 	ret = vsnprintf(NULL, 0, fmt, ap);
721 	strbuf = (char *)malloc(ret + 1);
722 	if (strbuf == NULL) {
723 		errno = ENOMEM;
724 		ret = -1;
725 	}
726 	vsnprintf(strbuf, ret + 1, fmt, ap);
727 	*strp = strbuf;
728 	return ret;
729 }
730 #endif
731 
732 #ifndef HAVE_ASPRINTF
asprintf(char ** strp,const char * fmt,...)733 int asprintf(char **strp, const char *fmt, ...)
734 {
735 	int ret;
736 	va_list ap;
737 
738 	va_start(ap, fmt);
739 	ret = vasprintf(strp, fmt, ap);
740 	va_end(ap);
741 
742 	return ret;
743 }
744 #endif
745 
746 #ifndef HAVE_ERROR
error(int status,int errornum,const char * fmt,...)747 void error(int status, int errornum, const char *fmt, ...)
748 {
749 	char *buf2;
750 	va_list ap;
751 
752 	va_start(ap, fmt);
753 	vasprintf(&buf2, fmt, ap);
754 	va_end(ap);
755 	fprintf(stderr, "%s", buf2);
756 	if (errornum)
757 		fprintf(stderr, ": %s\n", strerror(errornum));
758 	else
759 		fprintf(stderr, "\n");
760 	free(buf2);
761 
762 	if (status)
763 		exit(status);
764 }
765 #endif
766 
767 #ifndef HAVE_GETLINE
getline(char ** line,size_t * length,FILE * stream)768 int getline(char **line, size_t * length, FILE * stream)
769 {
770 	size_t len;
771 #ifdef HAVE_FGETLN
772 	char *tmpline;
773 
774 	tmpline = fgetln(stream, &len);
775 #else
776 	char tmpline[512];
777 
778 	fgets(tmpline, sizeof(tmpline), stream);
779 	len = strlen(tmpline);
780 #endif
781 	if (feof(stream))
782 		return -1;
783 	if (*line == NULL) {
784 		*line = malloc(len + 1);
785 		*length = len + 1;
786 	}
787 	if (*length < len + 1) {
788 		*line = realloc(*line, len + 1);
789 		*length = len + 1;
790 	}
791 	if (*line == NULL)
792 		return -1;
793 	memcpy(*line, tmpline, len);
794 	(*line)[len] = '\0';
795 	return len;
796 }
797 #endif
798 
799 #ifndef HAVE_UNSETENV
unsetenv(const char * name)800 int unsetenv(const char *name)
801 {
802 	int i, len;
803 
804 	len = strlen(name);
805 	for (i = 0; environ[i]; i++)
806 		if (!strncmp(name, environ[i], len))
807 			if (environ[i][len] == '=')
808 				break;
809 
810 	for (; environ[i] && environ[i + 1]; i++)
811 		environ[i] = environ[i + 1];
812 
813 	return 0;
814 }
815 #endif
816 
817 #ifndef HAVE_SETENV
setenv(const char * name,const char * value,int overwrite)818 int setenv(const char *name, const char *value, int overwrite)
819 {
820 	int ret;
821 	char *newenv;
822 
823 	if (overwrite == 0)
824 		if (getenv(name) != NULL)
825 			return 0;
826 
827 	newenv = malloc(strlen(name) + 1 + strlen(value) + 1);
828 	if (newenv == NULL)
829 		return -1;
830 
831 	*newenv = '\0';
832 	strcat(newenv, name);
833 	strcat(newenv, "=");
834 	strcat(newenv, value);
835 
836 	ret = putenv(newenv);
837 	if (ret == -1)
838 		free(newenv);
839 
840 	return ret;
841 }
842 #endif
843