3
* $Id: x99_util.c,v 1.12 2004/02/26 19:04:37 aland Exp $
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.
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.
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
19
* Copyright 2001,2002 Google, Inc.
31
#include <sys/types.h>
35
#include <openssl/des.h> /* des_cblock */
38
static const char rcsid[] = "$Id: x99_util.c,v 1.12 2004/02/26 19:04:37 aland Exp $";
41
/* Card name to int mappings */
46
{ "x9.9", CRYPTOCARD_H8_RC },
47
{ "generic", CRYPTOCARD_H8_RC },
49
{ "cryptocard-h8-rc", CRYPTOCARD_H8_RC },
50
{ "cryptocard-d8-rc", CRYPTOCARD_D8_RC },
51
{ "cryptocard-h7-rc", CRYPTOCARD_H7_RC },
52
{ "cryptocard-d7-rc", CRYPTOCARD_D7_RC },
53
{ "cryptocard-h8-es", CRYPTOCARD_H8_ES },
54
{ "cryptocard-d8-es", CRYPTOCARD_D8_ES },
55
{ "cryptocard-h7-es", CRYPTOCARD_H7_ES },
56
{ "cryptocard-d7-es", CRYPTOCARD_D7_ES },
57
{ "cryptocard-h8-rs", CRYPTOCARD_H8_RS },
58
{ "cryptocard-d8-rs", CRYPTOCARD_D8_RS },
59
{ "cryptocard-h7-rs", CRYPTOCARD_H7_RS },
60
{ "cryptocard-d7-rs", CRYPTOCARD_D7_RS },
62
{ NULL, 0 } /* end of list */
67
* Return a random challenge.
68
* fd must be either -1 or an open fd to the random device.
69
* challenge is filled in on successful return (must be size len+1).
70
* Returns 0 on success, -1 on failure.
73
x99_get_challenge(int fd, char *challenge, int len)
75
unsigned char rawchallenge[MAX_CHALLENGE_LEN];
79
if ((fd = open(DEVURANDOM, O_RDONLY)) == -1) {
80
x99_log(X99_LOG_ERR, "error opening %s: %s", DEVURANDOM,
86
if (x99_get_random(fd, rawchallenge, len) == -1) {
87
x99_log(X99_LOG_ERR, "failed to obtain random data");
90
/* Convert the raw bytes to a decimal string. */
91
for (i = 0; i < len; ++i)
92
challenge[i] = '0' + rawchallenge[i] % 10;
99
* Return some number of random bytes.
100
* rnd_data must be allocated by the caller.
101
* Returns 0 on success, -1 on failure, rnd_data is filled in.
104
x99_get_random(int fd, unsigned char *rnd_data, int req_bytes)
108
while (bytes_read < req_bytes) {
111
n = read(fd, rnd_data + bytes_read, req_bytes - bytes_read);
113
x99_log(X99_LOG_ERR, "x99_get_random: error reading from %s: %s",
114
DEVURANDOM, strerror(errno));
125
* Convert the ASCII string representation of a DES key to raw octets.
126
* keyblock is filled in. Returns 0 on success, -1 otherwise.
129
x99_string_to_keyblock(const char *s, des_cblock keyblock)
133
if (s == NULL || strlen(s) < 16)
137
* We could just use sscanf, but we do this a lot, and have very
138
* specific needs, and it's easy to implement, so let's go for it!
140
for (i = 0; i < 8; ++i) {
146
n[0] -= 'a' - '9' - 1;
149
n[1] -= 'a' - '9' - 1;
152
keyblock[i] = n[0] << 4;
159
/* Character maps for generic hex and vendor specific decimal modes */
160
const char x99_hex_conversion[] = "0123456789abcdef";
161
const char x99_cc_dec_conversion[] = "0123456789012345";
162
const char x99_snk_dec_conversion[] = "0123456789222333";
163
const char x99_sc_friendly_conversion[] = "0123456789ahcpef";
166
* Convert a DES keyblock to an ASCII string.
167
* Fills in s, which must point to at least 17 bytes of space.
168
* Note that each octet expands into 2 hex digits in ASCII (0xAA -> 0x4141);
169
* add a NULL string terminator and you get the 17 byte requirement.
172
x99_keyblock_to_string(char *s, const des_cblock keyblock,
173
const char conversion[17])
177
for (i = 0; i < 8; ++i) {
180
n[0] = (keyblock[i] >> 4) & 0x0f;
181
n[1] = keyblock[i] & 0x0f;
182
s[2 * i + 0] = conversion[n[0]];
183
s[2 * i + 1] = conversion[n[1]];
190
* fillin user_info from our database (key file)
191
* returns 0 on success, -1 for user not found, -2 for other errors.
194
x99_get_user_info(const char *pwdfile, const char *username,
195
x99_user_info_t *user_info)
203
/* Verify permissions first. */
204
if (stat(pwdfile, &st) != 0) {
205
x99_log(X99_LOG_ERR, "x99_get_user_info: pwdfile %s error: %s",
206
pwdfile, strerror(errno));
209
if ((st.st_mode & (S_IXUSR|S_IRWXG|S_IRWXO)) != 0) {
211
"x99_get_user_info: pwdfile %s has loose permissions", pwdfile);
215
if ((fp = fopen(pwdfile, "r")) == NULL) {
216
x99_log(X99_LOG_ERR, "x99_get_user_info: error opening %s: %s",
217
pwdfile, strerror(errno));
222
* Find the requested user.
223
* Add a ':' to the username to make sure we don't match shortest prefix.
225
p = malloc(strlen(username) + 2);
227
x99_log(X99_LOG_CRIT, "x99_get_user_info: out of memory");
230
(void) sprintf(p, "%s:", username);
233
if (fgets(s, sizeof(s), fp) == NULL) {
236
"x99_get_user_info: error reading from %s: %s",
237
pwdfile, strerror(errno));
242
} else if (!strncmp(s, p, strlen(p))) {
251
/* Noisy ... let the caller report this. */
252
x99_log(X99_LOG_AUTH, "x99_get_user_info: [%s] not found in %s",
258
/* Found him, skip to next field (card). */
259
if ((p = strchr(s, ':')) == NULL) {
261
"x99_get_user_info: invalid format for [%s] in %s",
267
if ((q = strchr(p, ':')) == NULL) {
269
"x99_get_user_info: invalid format for [%s] in %s",
274
/* p: card_type, q: key */
276
/* Match against card types. */
278
for (i = 0; card[i].name; ++i) {
279
if (!strcasecmp(p, card[i].name)) {
281
user_info->card_id = card[i].id;
287
"x99_get_user_info: unknown card %s for [%s] in %s",
288
p, username, pwdfile);
292
if (!(strlen(q) == 16 || (strlen(q) == 17 && q[16] == '\n'))) {
293
/* 8 octets + possible trailing newline */
294
x99_log(X99_LOG_ERR, "x99_get_user_info: invalid key for [%s] in %s",
299
/* Convert the key from ASCII to a keyblock. (+translate error code) */
300
return x99_string_to_keyblock(q, user_info->keyblock) * -2;