1 /*
2  * missing.c	Replacements for functions that are or can be
3  *		missing on some platforms.
4  *
5  * Version:	$Id: 95b8c54266109031177335184206ca0c7e3e473c $
6  *
7  *   This library is free software; you can redistribute it and/or
8  *   modify it under the terms of the GNU Lesser General Public
9  *   License as published by the Free Software Foundation; either
10  *   version 2.1 of the License, or (at your option) any later version.
11  *
12  *   This library is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  *   Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public
18  *   License along with this library; if not, write to the Free Software
19  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * Copyright 2000,2006  The FreeRADIUS server project
22  */
23 
24 RCSID("$Id: 95b8c54266109031177335184206ca0c7e3e473c $")
25 
26 #include	<freeradius-devel/libradius.h>
27 
28 #include	<ctype.h>
29 
30 #ifndef HAVE_CRYPT
crypt(UNUSED char * key,char * salt)31 char *crypt(UNUSED char *key, char *salt)
32 {
33 	/*log(L_ERR, "crypt() called but not implemented");*/
34 	return salt;
35 }
36 #endif
37 
38 #ifndef HAVE_STRNCASECMP
strncasecmp(char * s1,char * s2,int n)39 int strncasecmp(char *s1, char *s2, int n)
40 {
41 	int		dif;
42 	unsigned char	*p1, *p2;
43 	int		c1, c2;
44 
45 	p1 = (unsigned char *)s1;
46 	p2 = (unsigned char *)s2;
47 	dif = 0;
48 
49 	while (n != 0) {
50 		if (*p1 == 0 && *p2 == 0)
51 			break;
52 		c1 = *p1;
53 		c2 = *p2;
54 
55 		if (islower(c1)) c1 = toupper(c1);
56 		if (islower(c2)) c2 = toupper(c2);
57 
58 		if ((dif = c1 - c2) != 0)
59 			break;
60 		p1++;
61 		p2++;
62 		n--;
63 	}
64 	return dif;
65 }
66 #endif
67 
68 #ifndef HAVE_STRCASECMP
strcasecmp(char * s1,char * s2)69 int strcasecmp(char *s1, char *s2)
70 {
71 	int		l1, l2;
72 
73 	l1 = strlen(s1);
74 	l2 = strlen(s2);
75 	if (l2 > l1) l1 = l2;
76 
77 	return strncasecmp(s1, s2, l1);
78 }
79 #endif
80 
81 #ifndef HAVE_INET_ATON
inet_aton(char const * cp,struct in_addr * inp)82 int inet_aton(char const *cp, struct in_addr *inp)
83 {
84 	int	a1, a2, a3, a4;
85 
86 	if (sscanf(cp, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) != 4)
87 		return 0;
88 
89 	inp->s_addr = htonl((a1 << 24) + (a2 << 16) + (a3 << 8) + a4);
90 	return 1;
91 }
92 #endif
93 
94 #ifndef HAVE_STRSEP
95 /*
96  *	Get next token from string *stringp, where tokens are
97  *	possibly-empty strings separated by characters from delim.
98  *
99  *	Writes NULs into the string at *stringp to end tokens.
100  *	delim need not remain constant from call to call.  On
101  *	return, *stringp points past the last NUL written (if there
102  *	might be further tokens), or is NULL (if there are
103  *	definitely no more tokens).
104  *
105  *	If *stringp is NULL, strsep returns NULL.
106  */
107 char *
strsep(char ** stringp,char const * delim)108 strsep(char **stringp, char const *delim)
109 {
110 	char *s;
111 	char const *spanp;
112 	int c, sc;
113 	char *tok;
114 
115 	if ((s = *stringp) == NULL)
116 		return (NULL);
117 
118 	for (tok = s;;) {
119 		c = *s++;
120 		spanp = delim;
121 		do {
122 			if ((sc = *spanp++) == c) {
123 				if (c == 0)
124 					s = NULL;
125 				else
126 					s[-1] = 0;
127 				*stringp = s;
128 				return (tok);
129 			}
130 		} while (sc != 0);
131 	}
132 
133 	return NULL;		/* NOTREACHED, but the compiler complains */
134 }
135 #endif
136 
137 #ifndef HAVE_LOCALTIME_R
138 /*
139  *	We use localtime_r() by default in the server.
140  *
141  *	For systems which do NOT have localtime_r(), we make the
142  *	assumption that localtime() is re-entrant, and returns a
143  *	per-thread data structure.
144  *
145  *	Even if localtime is NOT re-entrant, this function will
146  *	lower the possibility of race conditions.
147  */
localtime_r(time_t const * l_clock,struct tm * result)148 struct tm *localtime_r(time_t const *l_clock, struct tm *result)
149 {
150   memcpy(result, localtime(l_clock), sizeof(*result));
151 
152   return result;
153 }
154 #endif
155 
156 #ifndef HAVE_CTIME_R
157 /*
158  *	We use ctime_r() by default in the server.
159  *
160  *	For systems which do NOT have ctime_r(), we make the
161  *	assumption that ctime() is re-entrant, and returns a
162  *	per-thread data structure.
163  *
164  *	Even if ctime is NOT re-entrant, this function will
165  *	lower the possibility of race conditions.
166  */
ctime_r(time_t const * l_clock,char * l_buf)167 char *ctime_r(time_t const *l_clock, char *l_buf)
168 {
169   strcpy(l_buf, ctime(l_clock));
170 
171   return l_buf;
172 }
173 #endif
174 
175 #ifndef HAVE_GMTIME_R
176 /*
177  *	We use gmtime_r() by default in the server.
178  *
179  *	For systems which do NOT have gmtime_r(), we make the
180  *	assumption that gmtime() is re-entrant, and returns a
181  *	per-thread data structure.
182  *
183  *	Even if gmtime is NOT re-entrant, this function will
184  *	lower the possibility of race conditions.
185  */
gmtime_r(time_t const * l_clock,struct tm * result)186 struct tm *gmtime_r(time_t const *l_clock, struct tm *result)
187 {
188   memcpy(result, gmtime(l_clock), sizeof(*result));
189 
190   return result;
191 }
192 #endif
193 
194 #ifndef HAVE_VDPRINTF
vdprintf(int fd,char const * format,va_list args)195 int vdprintf (int fd, char const *format, va_list args)
196 {
197 	int     ret;
198 	FILE    *fp;
199 	int	dup_fd;
200 
201 	dup_fd = dup(fd);
202 	if (dup_fd < 0) return -1;
203 
204 	fp = fdopen(fd, "w");
205 	if (!fp) {
206 		close(dup_fd);
207 		return -1;
208 	}
209 
210 	ret = vfprintf(fp, format, args);
211 	fclose(fp);	/* Also closes dup_fd */
212 
213 	return ret;
214 }
215 #endif
216 
217 #ifndef HAVE_GETTIMEOFDAY
218 #ifdef WIN32
219 /*
220  * Number of micro-seconds between the beginning of the Windows epoch
221  * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970).
222  *
223  * This assumes all Win32 compilers have 64-bit support.
224  */
225 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__WATCOMC__)
226 #define DELTA_EPOCH_IN_USEC  11644473600000000Ui64
227 #else
228 #define DELTA_EPOCH_IN_USEC  11644473600000000ULL
229 #endif
230 
filetime_to_unix_epoch(FILETIME const * ft)231 static uint64_t filetime_to_unix_epoch (FILETIME const *ft)
232 {
233 	uint64_t res = (uint64_t) ft->dwHighDateTime << 32;
234 
235 	res |= ft->dwLowDateTime;
236 	res /= 10;		   /* from 100 nano-sec periods to usec */
237 	res -= DELTA_EPOCH_IN_USEC;  /* from Win epoch to Unix epoch */
238 	return (res);
239 }
240 
gettimeofday(struct timeval * tv,UNUSED void * tz)241 int gettimeofday (struct timeval *tv, UNUSED void *tz)
242 {
243 	FILETIME  ft;
244 	uint64_t tim;
245 
246 	if (!tv) {
247 		errno = EINVAL;
248 		return (-1);
249 	}
250 	GetSystemTimeAsFileTime (&ft);
251 	tim = filetime_to_unix_epoch (&ft);
252 	tv->tv_sec  = (long) (tim / 1000000L);
253 	tv->tv_usec = (long) (tim % 1000000L);
254 	return (0);
255 }
256 #endif
257 #endif
258 
259 #define NTP_EPOCH_OFFSET	2208988800ULL
260 
261 /*
262  *	Convert 'struct timeval' into NTP format (32-bit integer
263  *	of seconds, 32-bit integer of fractional seconds)
264  */
265 void
timeval2ntp(struct timeval const * tv,uint8_t * ntp)266 timeval2ntp(struct timeval const *tv, uint8_t *ntp)
267 {
268 	uint32_t sec, usec;
269 
270 	sec = tv->tv_sec + NTP_EPOCH_OFFSET;
271 	usec = tv->tv_usec * 4295; /* close enough to 2^32 / USEC */
272 	usec -= ((tv->tv_usec * 2143) >> 16); /*  */
273 
274 	sec = htonl(sec);
275 	usec = htonl(usec);
276 
277 	memcpy(ntp, &sec, sizeof(sec));
278 	memcpy(ntp + sizeof(sec), &usec, sizeof(usec));
279 }
280 
281 /*
282  *	Inverse of timeval2ntp
283  */
284 void
ntp2timeval(struct timeval * tv,char const * ntp)285 ntp2timeval(struct timeval *tv, char const *ntp)
286 {
287 	uint32_t sec, usec;
288 
289 	memcpy(&sec, ntp, sizeof(sec));
290 	memcpy(&usec, ntp + sizeof(sec), sizeof(usec));
291 
292 	sec = ntohl(sec);
293 	usec = ntohl(usec);
294 
295 	tv->tv_sec = sec - NTP_EPOCH_OFFSET;
296 	tv->tv_usec = usec / 4295; /* close enough */
297 }
298 
299 #if !defined(HAVE_128BIT_INTEGERS) && defined(FR_LITTLE_ENDIAN)
300 /** Swap byte order of 128 bit integer
301  *
302  * @param num 128bit integer to swap.
303  * @return 128bit integer reversed.
304  */
ntohlll(uint128_t const num)305 uint128_t ntohlll(uint128_t const num)
306 {
307 	uint64_t const *p = (uint64_t const *) &num;
308 	uint64_t ret[2];
309 
310 	/* swapsies */
311 	ret[1] = ntohll(p[0]);
312 	ret[0] = ntohll(p[1]);
313 
314 	return *(uint128_t *)ret;
315 }
316 #endif
317 
318 #ifdef HAVE_OPENSSL_HMAC_H
319 #  ifndef HAVE_HMAC_CTX_NEW
HMAC_CTX_new(void)320 HMAC_CTX *HMAC_CTX_new(void)
321 {
322 	HMAC_CTX *ctx;
323 	ctx = OPENSSL_malloc(sizeof(*ctx));
324 	if (!ctx) return NULL;
325 
326 	memset(ctx, 0, sizeof(*ctx));
327         HMAC_CTX_init(ctx);
328 	return ctx;
329 }
330 #  endif
331 #  ifndef HAVE_HMAC_CTX_FREE
HMAC_CTX_free(HMAC_CTX * ctx)332 void HMAC_CTX_free(HMAC_CTX *ctx)
333 {
334         if (ctx == NULL) {
335                 return;
336         }
337         HMAC_CTX_cleanup(ctx);
338         OPENSSL_free(ctx);
339 }
340 #  endif
341 #endif
342 
343 #ifdef HAVE_OPENSSL_SSL_H
344 #  ifndef HAVE_SSL_GET_CLIENT_RANDOM
SSL_get_client_random(const SSL * s,unsigned char * out,size_t outlen)345 size_t SSL_get_client_random(const SSL *s, unsigned char *out, size_t outlen)
346 {
347 	if (!outlen) return sizeof(s->s3->client_random);
348 
349 	if (outlen > sizeof(s->s3->client_random)) outlen = sizeof(s->s3->client_random);
350 
351 	memcpy(out, s->s3->client_random, outlen);
352 	return outlen;
353 }
354 #  endif
355 #  ifndef HAVE_SSL_GET_SERVER_RANDOM
SSL_get_server_random(const SSL * s,unsigned char * out,size_t outlen)356 size_t SSL_get_server_random(const SSL *s, unsigned char *out, size_t outlen)
357 {
358 	if (!outlen) return sizeof(s->s3->server_random);
359 
360 	if (outlen > sizeof(s->s3->server_random)) outlen = sizeof(s->s3->server_random);
361 
362 	memcpy(out, s->s3->server_random, outlen);
363 	return outlen;
364 }
365 #  endif
366 #  ifndef HAVE_SSL_SESSION_GET_MASTER_KEY
SSL_SESSION_get_master_key(const SSL_SESSION * s,unsigned char * out,size_t outlen)367 size_t SSL_SESSION_get_master_key(const SSL_SESSION *s,
368 				  unsigned char *out, size_t outlen)
369 {
370 	if (!outlen) return s->master_key_length;
371 
372 	if (outlen > (size_t)s->master_key_length) outlen = (size_t)s->master_key_length;
373 
374 	memcpy(out, s->master_key, outlen);
375 	return outlen;
376 }
377 #  endif
378 #endif
379 
380 /** Call talloc strdup, setting the type on the new chunk correctly
381  *
382  * For some bizarre reason the talloc string functions don't set the
383  * memory chunk type to char, which causes all kinds of issues with
384  * verifying VALUE_PAIRs.
385  *
386  * @param[in] t The talloc context to hang the result off.
387  * @param[in] p The string you want to duplicate.
388  * @return The duplicated string, NULL on error.
389  */
talloc_typed_strdup(void const * t,char const * p)390 char *talloc_typed_strdup(void const *t, char const *p)
391 {
392 	char *n;
393 
394 	n = talloc_strdup(t, p);
395 	if (!n) return NULL;
396 	talloc_set_type(n, char);
397 
398 	return n;
399 }
400 
401 /** Call talloc vasprintf, setting the type on the new chunk correctly
402  *
403  * For some bizarre reason the talloc string functions don't set the
404  * memory chunk type to char, which causes all kinds of issues with
405  * verifying VALUE_PAIRs.
406  *
407  * @param[in] t The talloc context to hang the result off.
408  * @param[in] fmt The format string.
409  * @return The formatted string, NULL on error.
410  */
talloc_typed_asprintf(void const * t,char const * fmt,...)411 char *talloc_typed_asprintf(void const *t, char const *fmt, ...)
412 {
413 	char *n;
414 	va_list ap;
415 
416 	va_start(ap, fmt);
417 	n = talloc_vasprintf(t, fmt, ap);
418 	va_end(ap);
419 	if (!n) return NULL;
420 	talloc_set_type(n, char);
421 
422 	return n;
423 }
424 
425 /** Binary safe strndup function
426  *
427  * @param[in] t The talloc context o allocate new buffer in.
428  * @param[in] in String to dup, may contain embedded '\0'.
429  * @param[in] inlen Number of bytes to dup.
430  * @return duped string.
431  */
talloc_bstrndup(void const * t,char const * in,size_t inlen)432 char *talloc_bstrndup(void const *t, char const *in, size_t inlen)
433 {
434 	char *p;
435 
436 	p = talloc_array(t, char, inlen + 1);
437 	if (!p) return NULL;
438 	memcpy(p, in, inlen);
439 	p[inlen] = '\0';
440 
441 	return p;
442 }
443 
444