1 /*
2     MiddleMan filtering proxy server
3     Copyright (C) 2002  Jason McLaughlin
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <netinet/in.h>
26 #include <sys/time.h>
27 #include <sys/wait.h>
28 #include <sys/types.h>
29 #include <sys/mman.h>
30 #include <netdb.h>
31 #include "proto.h"
32 
33 extern char **environ;
34 
35 #ifdef HAVE_GETHOSTBYNAME_R
36 
37 /*
38 wrapper for reentrant gethostbyname function
39 */
p_gethostbyname(char * host)40 HOSTENT *p_gethostbyname(char *host)
41 {
42 	int ret, err;
43 	char buf[1024];
44 	HOSTENT *hostent;
45 	struct hostent h, *hp;
46 
47 	ret = gethostbyname_r(host, &h, buf, sizeof(buf), &hp, &err);
48 	if (hp == NULL)
49 		return NULL;
50 
51 	hostent = xmalloc(sizeof(HOSTENT));
52 	hostent->addr = xmalloc(sizeof(struct in_addr));
53 	memcpy(hostent->addr, hp->h_addr_list[0], sizeof(struct in_addr));
54 	hostent->len = sizeof(struct in_addr);
55 
56 	return hostent;
57 }
58 
59 #else
60 
61 /*
62 stupid work-around for systems without gethostbyname_r
63 */
p_gethostbyname(char * host)64 HOSTENT *p_gethostbyname(char *host)
65 {
66 	HOSTENT *hostent;
67 	struct hostent *h;
68 	static pthread_mutex_t gethostbyname_mutex = PTHREAD_MUTEX_INITIALIZER;
69 
70 	pthread_mutex_lock(&gethostbyname_mutex);
71 
72 	h = gethostbyname(host);
73 	if (h == NULL) {
74 		pthread_mutex_unlock(&gethostbyname_mutex);
75 
76 		return NULL;
77 	}
78 
79 	hostent = xmalloc(sizeof(HOSTENT));
80 	hostent->addr = xmalloc(h->h_length);
81 	memcpy(hostent->addr, h->h_addr_list[0], h->h_length);
82 	hostent->len = h->h_length;
83 
84 	pthread_mutex_unlock(&gethostbyname_mutex);
85 
86 	return hostent;
87 }
88 
89 #endif				/* HAVE_GETHOSTBYNAME_R */
90 
91 #ifdef HAVE_POLL
92 
93 /*
94 wrapper for poll() for systems that actually implement this
95 */
p_poll(struct pollfd * pollfd,int fds,int timeout)96 int p_poll(struct pollfd *pollfd, int fds, int timeout)
97 {
98 	return poll(pollfd, fds, timeout);
99 }
100 
101 #else
102 
103 /*
104 basic poll() wrapper using select for system's lacking that feature
105 */
p_poll(struct pollfd * pfd,int fds,int timeout)106 int p_poll(struct pollfd *pfd, int fds, int timeout)
107 {
108 	int i, ret, hfd = 0;
109 	fd_set readlist, writelist;
110 	struct timeval tv;
111 
112 	FD_ZERO(&readlist);
113 	FD_ZERO(&writelist);
114 
115 	if (timeout >= 0) {
116 		tv.tv_usec = timeout * 1000;
117 		tv.tv_sec = tv.tv_usec / 1000000;
118 		tv.tv_usec %= 1000000;
119 	}
120 
121 	for (i = 0; i < fds; i++) {
122 		if (pfd[i].fd >= hfd)
123 			hfd = pfd[i].fd + 1;
124 
125 		pfd[i].revents = 0;
126 
127 		if (pfd[i].events & POLLIN)
128 			FD_SET(pfd[i].fd, &readlist);
129 
130 		if (pfd[i].events & POLLOUT)
131 			FD_SET(pfd[i].fd, &writelist);
132 	}
133 
134 	ret = select(hfd, &readlist, &writelist, NULL, (timeout >= 0) ? &tv : NULL);
135 
136 	if (ret > 0) {
137 		for (i = 0; i < fds; i++) {
138 			if (FD_ISSET(pfd[i].fd, &readlist))
139 				pfd[i].revents |= POLLIN;
140 
141 			if (FD_ISSET(pfd[i].fd, &writelist))
142 				pfd[i].revents |= POLLOUT;
143 
144 			if (fcntl(pfd[i].fd, F_GETFL, O_NDELAY) == -1)
145 				pfd[i].revents |= POLLHUP;
146 		}
147 	}
148 
149 	return ret;
150 }
151 
152 #endif				/* HAVE_POLL */
153 
154 #ifdef HAVE_SETENV
155 
p_setenv(char * var,char * value,int overwrite)156 int p_setenv(char *var, char *value, int overwrite)
157 {
158 	return setenv(var, value, overwrite);
159 }
160 
161 #else
162 
163 /*
164 solaris, et al lack setenv(), this will emulate it's behavior
165 */
p_setenv(char * var,char * value,int overwrite)166 int p_setenv(char *var, char *value, int overwrite)
167 {
168 	char *buf;
169 
170 	if (!overwrite && getenv(var))
171 		return -1;
172 
173 	buf = xmalloc(strlen(var) + strlen(value) + 2);
174 
175 	sprintf(buf, "%s=%s", var, value);
176 
177 	return putenv(buf);
178 }
179 
180 #endif				/* HAVE_SETENV */
181 
182 
183 /*
184 clearenv() is glibc-specific, setting environ to NULL will do for other platforms
185 */
p_clearenv()186 void p_clearenv()
187 {
188 #ifdef HAVE_CLEARENV
189 	clearenv();
190 #else
191 	environ = NULL;
192 #endif
193 }
194 
195 #ifdef HAVE_MREMAP
p_mremap(void * old_address,size_t old_size,size_t new_size,int fd)196 void *p_mremap(void *old_address, size_t old_size, size_t new_size, int fd)
197 {
198         return mremap(old_address, old_size, new_size, MREMAP_MAYMOVE);
199 }
200 #else
p_mremap(void * old_address,size_t old_size,size_t new_size,int fd)201 void *p_mremap(void *old_address, size_t old_size, size_t new_size, int fd)
202 {
203         void *ptr;
204 
205         if (fd != -1) {
206                 /* unmap and remap file */
207                 munmap(old_address, old_size);
208                 ptr = mmap(NULL, new_size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
209         } else {
210                 ptr = mmap(NULL, new_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
211                 if (ptr != MAP_FAILED) {
212                         memcpy(ptr, old_address, (new_size < old_size) ? new_size : old_size);
213 
214                         munmap(old_address, old_size);
215                 } else
216                         munmap(old_address, old_size);
217         }
218 
219         return ptr;
220 }
221 #endif
222 
223