type.data is malloc'd by everyone BUT radeapclient, which
[freeradius.git] / src / modules / rlm_otp / otp_util.c
1 /*
2  * $Id$
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program; if not, write to the Free Software
16  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  * Copyright 2001,2002  Google, Inc.
19  * Copyright 2005,2006 TRI-D Systems, Inc.
20  */
21
22 #include "ident.h"
23 RCSID("$Id$")
24
25 #include "extern.h"
26
27 #include <inttypes.h>
28 #include <pthread.h>
29 #include <sys/types.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 /*
34  * Return some random bytes.
35  */
36 void
37 otp_get_random(char *rnd_data, size_t len)
38 {
39   size_t bytes_read = 0;
40
41   while (bytes_read < len) {
42     int n;
43     unsigned int bytes_left = len - bytes_read;
44     uint32_t r = lrad_rand();
45
46     n = sizeof(r) < bytes_left ? sizeof(r) : bytes_left;
47     (void) memcpy(rnd_data + bytes_read, &r, n);
48     bytes_read += n;
49   }
50 }
51
52 /*
53  * Return a random challenge.
54  * NOTE: This is really cryptocard-specific (automatic ASCII conversion
55  *        and null termination).
56  */
57 void
58 otp_async_challenge(char challenge[OTP_MAX_CHALLENGE_LEN + 1], int len)
59 {
60   unsigned char rawchallenge[OTP_MAX_CHALLENGE_LEN];
61   int i;
62
63   otp_get_random(rawchallenge, len);
64
65   /* Convert the raw bytes to ASCII decimal. */
66   for (i = 0; i < len; ++i)
67     challenge[i] = '0' + rawchallenge[i] % 10;
68   challenge[len] = '\0';
69 }
70
71 /* ascii to hex; returns HEXlen on success or -1 on error */
72 int
73 otp_a2x(const char *s, unsigned char x[])
74 {
75   unsigned i;
76   size_t l = strlen(s);
77
78   /*
79    * We could just use sscanf, but we do this a lot, and have very
80    * specific needs, and it's easy to implement, so let's go for it!
81    */
82   for (i = 0; i < l / 2; ++i) {
83     unsigned int n[2];
84     int j;
85
86     /* extract 2 nibbles */
87     n[0] = *s++;
88     n[1] = *s++;
89
90     /* verify range */
91     for (j = 0; j < 2; ++j) {
92       if ((n[j] >= '0' && n[j] <= '9') ||
93           (n[j] >= 'A' && n[j] <= 'F') ||
94           (n[j] >= 'a' && n[j] <= 'f'))
95         continue;
96       return -1;
97     }
98
99     /* convert ASCII hex digits to numeric values */
100     n[0] -= '0';
101     n[1] -= '0';
102     if (n[0] > 9) {
103       if (n[0] > 'F' - '0')
104         n[0] -= 'a' - '9' - 1;
105       else
106         n[0] -= 'A' - '9' - 1;
107     }
108     if (n[1] > 9) {
109       if (n[1] > 'F' - '0')
110         n[1] -= 'a' - '9' - 1;
111       else
112         n[1] -= 'A' - '9' - 1;
113     }
114
115     /* store as octets */
116     x[i]  = n[0] << 4;
117     x[i] += n[1];
118   } /* for (each octet) */
119
120   return l/2;
121 }
122
123 /* Character maps for generic hex and vendor specific decimal modes */
124 static const char otp_hex_conversion[]         = "0123456789abcdef";
125 #if 0   /* just for reference */
126 static const char otp_cc_dec_conversion[]      = "0123456789012345";
127 static const char otp_snk_dec_conversion[]     = "0123456789222333";
128 static const char otp_sc_friendly_conversion[] = "0123456789ahcpef";
129 #endif
130
131 /*
132  * hex to ascii
133  * Fills in s, which must point to at least len*2+1 bytes of space.
134  */
135 void
136 otp_x2a(const unsigned char *x, size_t len, char *s)
137 {
138   unsigned i;
139
140   for (i = 0; i < len; ++i) {
141     unsigned n[2];
142
143     n[0] = (x[i] >> 4) & 0x0f;
144     n[1] = x[i] & 0x0f;
145     s[2 * i + 0] = otp_hex_conversion[n[0]];
146     s[2 * i + 1] = otp_hex_conversion[n[1]];
147   }
148   s[2 * len] = '\0';
149 }
150
151 /* guaranteed initialization */
152 void
153 _otp_pthread_mutex_init(pthread_mutex_t *mutexp,
154                         const pthread_mutexattr_t *attr, const char *caller)
155 {
156   int rc;
157
158   if ((rc = pthread_mutex_init(mutexp, attr))) {
159     (void) radlog(L_ERR|L_CONS,
160                   "rlm_otp: %s: pthread_mutex_init: %s", caller, strerror(rc));
161     exit(1);
162   }
163 }
164
165 /* guaranteed lock */
166 void
167 _otp_pthread_mutex_lock(pthread_mutex_t *mutexp, const char *caller)
168 {
169   int rc;
170
171   if ((rc = pthread_mutex_lock(mutexp))) {
172     (void) radlog(L_ERR|L_CONS,
173                   "rlm_otp: %s: pthread_mutex_lock: %s", caller, strerror(rc));
174     exit(1);
175   }
176 }
177
178 /* guaranteed trylock */
179 int
180 _otp_pthread_mutex_trylock(pthread_mutex_t *mutexp, const char *caller)
181 {
182   int rc;
183
184   rc = pthread_mutex_trylock(mutexp);
185   if (rc && rc != EBUSY) {
186     (void) radlog(L_ERR|L_CONS,
187                   "rlm_otp: %s: pthread_mutex_trylock: %s",
188                   caller, strerror(rc));
189     exit(1);
190   }
191
192   return rc;
193 }
194
195 /* guaranteed unlock */
196 void
197 _otp_pthread_mutex_unlock(pthread_mutex_t *mutexp, const char *caller)
198 {
199   int rc;
200
201   if ((rc = pthread_mutex_unlock(mutexp))) {
202     (void) radlog(L_ERR|L_CONS,
203                   "rlm_otp: %s: pthread_mutex_unlock: %s",
204                   caller, strerror(rc));
205     exit(1);
206   }
207 }