import from HEAD:
[freeradius.git] / src / lib / misc.c
1 /*
2  * misc.c       Various miscellaneous functions.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  */
22
23 static const char rcsid[] =
24 "$Id$";
25
26 #include        "autoconf.h"
27
28 #include        <stdio.h>
29 #include        <sys/types.h>
30 #include        <sys/socket.h>
31 #include        <netinet/in.h>
32 #include        <arpa/inet.h>
33
34 #include        <stdlib.h>
35 #include        <string.h>
36 #include        <netdb.h>
37 #include        <ctype.h>
38 #include        <sys/file.h>
39 #include        <fcntl.h>
40 #include        <unistd.h>
41
42 #include        "libradius.h"
43 #include        "missing.h"
44
45 int             librad_dodns = 0;
46 int             librad_debug = 0;
47
48
49 /*
50  *      Return a printable host name (or IP address in dot notation)
51  *      for the supplied IP address.
52  */
53 char * ip_hostname(char *buf, size_t buflen, uint32_t ipaddr)
54 {
55         struct          hostent *hp;
56 #ifdef GETHOSTBYADDRRSTYLE
57 #if (GETHOSTBYADDRRSTYLE == SYSVSTYLE) || (GETHOSTBYADDRRSTYLE == GNUSTYLE)
58         char buffer[2048];
59         struct hostent result;
60         int error;
61 #endif
62 #endif
63
64         /*
65          *      No DNS: don't look up host names
66          */
67         if (librad_dodns == 0) {
68                 ip_ntoa(buf, ipaddr);
69                 return buf;
70         }
71
72 #ifdef GETHOSTBYADDRRSTYLE
73 #if GETHOSTBYADDRRSTYLE == SYSVSTYLE
74         hp = gethostbyaddr_r((char *)&ipaddr, sizeof(struct in_addr), AF_INET, &result, buffer, sizeof(buffer), &error);
75 #elif GETHOSTBYADDRRSTYLE == GNUSTYLE
76         if (gethostbyaddr_r((char *)&ipaddr, sizeof(struct in_addr),
77                             AF_INET, &result, buffer, sizeof(buffer),
78                             &hp, &error) != 0) {
79                 hp = NULL;
80         }
81 #else
82         hp = gethostbyaddr((char *)&ipaddr, sizeof(struct in_addr), AF_INET);
83 #endif
84 #else
85         hp = gethostbyaddr((char *)&ipaddr, sizeof(struct in_addr), AF_INET);
86 #endif
87         if ((hp == NULL) ||
88             (strlen((char *)hp->h_name) >= buflen)) {
89                 ip_ntoa(buf, ipaddr);
90                 return buf;
91         }
92
93         strNcpy(buf, (char *)hp->h_name, buflen);
94         return buf;
95 }
96
97
98 /*
99  *      Return an IP address from a host
100  *      name or address in dot notation.
101  */
102 uint32_t ip_getaddr(const char *host)
103 {
104         struct hostent  *hp;
105         uint32_t         a;
106 #ifdef GETHOSTBYNAMERSTYLE
107 #if (GETHOSTBYNAMERSTYLE == SYSVSTYLE) || (GETHOSTBYNAMERSTYLE == GNUSTYLE)
108         struct hostent result;
109         int error;
110         char buffer[2048];
111 #endif
112 #endif
113
114         if ((a = ip_addr(host)) != htonl(INADDR_NONE))
115                 return a;
116
117 #ifdef GETHOSTBYNAMERSTYLE
118 #if GETHOSTBYNAMERSTYLE == SYSVSTYLE
119         hp = gethostbyname_r(host, &result, buffer, sizeof(buffer), &error);
120 #elif GETHOSTBYNAMERSTYLE == GNUSTYLE
121         if (gethostbyname_r(host, &result, buffer, sizeof(buffer),
122                             &hp, &error) != 0) {
123                 return htonl(INADDR_NONE);
124         }
125 #else
126         hp = gethostbyname(host);
127 #endif
128 #else
129         hp = gethostbyname(host);
130 #endif
131         if (hp == NULL) {
132                 return htonl(INADDR_NONE);
133         }
134
135         /*
136          *      Paranoia from a Bind vulnerability.  An attacker
137          *      can manipulate DNS entries to change the length of the
138          *      address.  If the length isn't 4, something's wrong.
139          */
140         if (hp->h_length != 4) {
141                 return htonl(INADDR_NONE);
142         }
143
144         memcpy(&a, hp->h_addr, sizeof(uint32_t));
145         return a;
146 }
147
148
149 /*
150  *      Return an IP address in standard dot notation
151  */
152 char *ip_ntoa(char *buffer, uint32_t ipaddr)
153 {
154         ipaddr = ntohl(ipaddr);
155
156         sprintf(buffer, "%d.%d.%d.%d",
157                 (ipaddr >> 24) & 0xff,
158                 (ipaddr >> 16) & 0xff,
159                 (ipaddr >>  8) & 0xff,
160                 (ipaddr      ) & 0xff);
161         return buffer;
162 }
163
164
165 /*
166  *      Return an IP address from
167  *      one supplied in standard dot notation.
168  */
169 uint32_t ip_addr(const char *ip_str)
170 {
171         struct in_addr  in;
172
173         if (inet_aton(ip_str, &in) == 0)
174                 return htonl(INADDR_NONE);
175         return in.s_addr;
176 }
177
178
179 /*
180  *      Like strncpy, but always adds \0
181  */
182 char *strNcpy(char *dest, const char *src, int n)
183 {
184         char *p = dest;
185
186         while ((n > 1) && (*src)) {
187                 *(p++) = *(src++);
188
189                 n--;
190         }
191         *p = '\0';
192
193         return dest;
194 }
195
196 /*
197  * Lowercase a string
198  */
199 void rad_lowercase(char *str) {
200         char *s;
201
202         for (s=str; *s; s++)
203                 if (isupper((int) *s)) *s = tolower((int) *s);
204 }
205
206 /*
207  * Remove spaces from a string
208  */
209 void rad_rmspace(char *str) {
210         char *s = str;
211         char *ptr = str;
212
213   while(ptr && *ptr!='\0') {
214     while(isspace((int) *ptr))
215       ptr++;
216     *s = *ptr;
217     ptr++;
218     s++;
219   }
220   *s = '\0';
221 }
222
223 /*
224  *      Internal wrapper for locking, to minimize the number of ifdef's
225  *
226  *      Lock an fd, prefer lockf() over flock()
227  */
228 int rad_lockfd(int fd, int lock_len)
229 {
230 #if defined(F_LOCK) && !defined(BSD)
231         return lockf(fd, F_LOCK, lock_len);
232 #elif defined(LOCK_EX)
233         return flock(fd, LOCK_EX);
234 #else
235         struct flock fl;
236         fl.l_start = 0;
237         fl.l_len = lock_len;
238         fl.l_pid = getpid();
239         fl.l_type = F_WRLCK;
240         fl.l_whence = SEEK_CUR;
241         return fcntl(fd, F_SETLKW, (void *)&fl);
242 #endif
243 }
244
245 /*
246  *      Internal wrapper for locking, to minimize the number of ifdef's
247  *
248  *      Lock an fd, prefer lockf() over flock()
249  *      Nonblocking version.
250  */
251 int rad_lockfd_nonblock(int fd, int lock_len)
252 {
253 #if defined(F_LOCK) && !defined(BSD)
254         return lockf(fd, F_TLOCK, lock_len);
255 #elif defined(LOCK_EX)
256         return flock(fd, LOCK_EX | LOCK_NB);
257 #else
258         struct flock fl;
259         fl.l_start = 0;
260         fl.l_len = lock_len;
261         fl.l_pid = getpid();
262         fl.l_type = F_WRLCK;
263         fl.l_whence = SEEK_CUR;
264         return fcntl(fd, F_SETLK, (void *)&fl);
265 #endif
266 }
267
268 /*
269  *      Internal wrapper for unlocking, to minimize the number of ifdef's
270  *      in the source.
271  *
272  *      Unlock an fd, prefer lockf() over flock()
273  */
274 int rad_unlockfd(int fd, int lock_len)
275 {
276 #if defined(F_LOCK) && !defined(BSD)
277         return lockf(fd, F_ULOCK, lock_len);
278 #elif defined(LOCK_EX)
279         return flock(fd, LOCK_UN);
280 #else
281         struct flock fl;
282         fl.l_start = 0;
283         fl.l_len = lock_len;
284         fl.l_pid = getpid();
285         fl.l_type = F_WRLCK;
286         fl.l_whence = SEEK_CUR;
287         return fcntl(fd, F_UNLCK, (void *)&fl);
288 #endif
289 }
290
291 /*
292  *      Return an interface-id in standard colon notation
293  */
294 char *ifid_ntoa(char *buffer, size_t size, uint8_t *ifid)
295 {
296         snprintf(buffer, size, "%x:%x:%x:%x",
297                  (ifid[0] << 8) + ifid[1], (ifid[2] << 8) + ifid[3],
298                  (ifid[4] << 8) + ifid[5], (ifid[6] << 8) + ifid[7]);
299         return buffer;
300 }
301
302
303 /*
304  *      Return an interface-id from
305  *      one supplied in standard colon notation.
306  */
307 uint8_t *ifid_aton(const char *ifid_str, uint8_t *ifid)
308 {
309         static const char xdigits[] = "0123456789abcdef";
310         const char *p, *pch;
311         int num_id = 0, val = 0, idx = 0;
312
313         for (p = ifid_str; ; ++p) {
314                 if (*p == ':' || *p == '\0') {
315                         if (num_id <= 0)
316                                 return NULL;
317
318                         /*
319                          *      Drop 'val' into the array.
320                          */
321                         ifid[idx] = (val >> 8) & 0xff;
322                         ifid[idx + 1] = val & 0xff;
323                         if (*p == '\0') {
324                                 /*
325                                  *      Must have all entries before
326                                  *      end of the string.
327                                  */
328                                 if (idx != 6)
329                                         return NULL;
330                                 break;
331                         }
332                         val = 0;
333                         num_id = 0;
334                         if ((idx += 2) > 6)
335                                 return NULL;
336                 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
337                         if (++num_id > 4)
338                                 return NULL;
339                         /*
340                          *      Dumb version of 'scanf'
341                          */
342                         val <<= 4;
343                         val |= (pch - xdigits);
344                 } else
345                         return NULL;
346         }
347         return ifid;
348 }
349 /*
350  *      Return an IPv6 address in standard colon notation
351  */
352 const char *ipv6_ntoa(char *buffer, size_t size, void *ip6addr)
353 {
354 #if defined(HAVE_INET_NTOP) && defined(AF_INET6)
355         return inet_ntop(AF_INET6, (struct in6_addr *) ip6addr, buffer, size);
356 #else
357         /*
358          *      Do it really stupidly.
359          */
360         snprintf(buffer, size, "%x:%x:%x:%x:%x:%x:%x:%x",
361                  (((uint8_t *) ip6addr)[0] << 8) | ((uint8_t *) ip6addr)[1],
362                  (((uint8_t *) ip6addr)[2] << 8) | ((uint8_t *) ip6addr)[3],
363                  (((uint8_t *) ip6addr)[4] << 8) | ((uint8_t *) ip6addr)[5],
364                  (((uint8_t *) ip6addr)[6] << 8) | ((uint8_t *) ip6addr)[7],
365                  (((uint8_t *) ip6addr)[8] << 8) | ((uint8_t *) ip6addr)[9],
366                  (((uint8_t *) ip6addr)[10] << 8) | ((uint8_t *) ip6addr)[11],
367                  (((uint8_t *) ip6addr)[12] << 8) | ((uint8_t *) ip6addr)[13],
368                  (((uint8_t *) ip6addr)[14] << 8) | ((uint8_t *) ip6addr)[15]);
369         return buffer;
370 #endif
371 }
372
373
374 /*
375  *      Return an IPv6 address from
376  *      one supplied in standard colon notation.
377  */
378 int ipv6_addr(const char *ip6_str, void *ip6addr)
379 {
380 #if defined(HAVE_INET_PTON) && defined(AF_INET6)
381         if (inet_pton(AF_INET6, ip6_str, (struct in6_addr *) ip6addr) != 1)
382                 return -1;
383 #else
384         /*
385          *      Copied from the 'ifid' code above, with minor edits.
386          */
387         static const char xdigits[] = "0123456789abcdef";
388         const char *p, *pch;
389         int num_id = 0, val = 0, idx = 0;
390         uint8_t *addr = ip6addr;
391
392         for (p = ip6_str; ; ++p) {
393                 if (*p == ':' || *p == '\0') {
394                         if (num_id <= 0)
395                                 return -1;
396
397                         /*
398                          *      Drop 'val' into the array.
399                          */
400                         addr[idx] = (val >> 8) & 0xff;
401                         addr[idx + 1] = val & 0xff;
402                         if (*p == '\0') {
403                                 /*
404                                  *      Must have all entries before
405                                  *      end of the string.
406                                  */
407                                 if (idx != 14)
408                                         return -1;
409                                 break;
410                         }
411                         val = 0;
412                         num_id = 0;
413                         if ((idx += 2) > 14)
414                                 return -1;
415                 } else if ((pch = strchr(xdigits, tolower(*p))) != NULL) {
416                         if (++num_id > 8) /* no more than 8 16-bit numbers */
417                                 return -1;
418                         /*
419                          *      Dumb version of 'scanf'
420                          */
421                         val <<= 4;
422                         val |= (pch - xdigits);
423                 } else
424                         return -1;
425         }
426 #endif
427         return 0;
428 }
429
430 static const char *hextab = "0123456789abcdef";
431
432 /*
433  *      hex2bin
434  *
435  *      We allow: hex == bin
436  */
437 int lrad_hex2bin(const char *hex, uint8_t *bin, int len)
438 {
439         int i;
440         char *c1, *c2;
441
442         for (i = 0; i < len; i++) {
443                 if(!(c1 = memchr(hextab, tolower((int) hex[i << 1]), 16)) ||
444                    !(c2 = memchr(hextab, tolower((int) hex[(i << 1) + 1]), 16)))
445                         break;
446                  bin[i] = ((c1-hextab)<<4) + (c2-hextab);
447         }
448
449         return i;
450 }
451
452
453 /*
454  *      bin2hex
455  *
456  *      If the output buffer isn't long enough, we have a buffer overflow.
457  */
458 void lrad_bin2hex(const uint8_t *bin, char *hex, int len)
459 {
460         int i;
461
462         for (i = 0; i < len; i++) {
463                 hex[0] = hextab[((*bin) >> 4) & 0x0f];
464                 hex[1] = hextab[*bin & 0x0f];
465                 hex += 2;
466                 bin++;
467         }
468         *hex = '\0';
469         return;
470 }
471
472 /*
473  *      So we don't have ifdef's in the rest of the code
474  */
475 #ifndef HAVE_CLOSEFROM
476 int closefrom(int fd)
477 {
478         int i;
479         int maxfd = 256;
480
481 #ifdef _SC_OPEN_MAX
482         maxfd = sysconf(_SC_OPEN_MAX);
483         if (maxfd < 0) {
484           maxfd = 256;
485         }
486 #endif
487
488         if (fd > maxfd) return 0;
489
490         /*
491          *      FIXME: return EINTR?
492          *
493          *      Use F_CLOSEM?
494          */
495         for (i = fd; i < maxfd; i++) {
496                 close(i);
497         }
498
499         return 0;
500 }
501 #endif