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