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 *) #
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