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