1
/* cryptocard.c - support for the CRYPTOCard
2
RB-1 Challenge-Response Token, initial code by
3
bentson@grieg.seaslug.org (Randolph Bentson) on 3-Dec-96,
4
Hacked severely by poe@daimi.aau.dk.
5
This relies on an implementation of DES in a library, currently
6
it interfaces with the koontz-des.tar.gz implementation which
9
ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/des/
11
(Link with the fdes.o file from that distribution)
13
and with Eric A. Young's libdes implementation used in SSLeay. Also
14
available from the above ftp site. Link with the libdes.a library.
16
The sources for this code are maintained in
18
ftp://ftp.daimi.aau.dk/pub/linux/poe/poeigl-X.XX.tar.gz
20
1999-02-22 Arkadiusz Mi�kiewicz <misiek@pld.ORG.PL>
21
- added Native Language Support
26
/******************** CONFIGURATION section *****************************/
27
/*--------------- select ONE DES implementation ------------------------*/
28
/*#define KOONTZ_DES */
30
/*--------------- define if on little endian machine (Intel x86) -------*/
32
/******************** end of CONFIGURATION section **********************/
45
#include <sys/param.h>
50
#include "../koontz-des/des.h"
51
#endif /* KOONTZ_DES */
54
#include "../libdes/des.h"
55
#endif /* EAY_LIBDES */
57
#include "cryptocard.h"
60
generate_challenge(void)
62
static char challenge_str[30];
66
/* create and present a challenge string */
67
if ((rfd = open("/dev/urandom", O_RDONLY)) < 0) {
68
syslog(LOG_NOTICE, _("couldn't open /dev/urandom"));
71
if (read(rfd, &clong, 4) < 4) {
73
syslog(LOG_NOTICE, _("couldn't read random data from /dev/urandom"));
78
sprintf(challenge_str,"%08lu", clong);
86
char keyfile[MAXPATHLEN];
91
if (strlen(pwd->pw_dir) + 13 > sizeof(keyfile))
93
sprintf(keyfile, "%s/.cryptocard", pwd->pw_dir);
95
if ((rfd = open(keyfile, O_RDONLY)) < 0) {
96
syslog(LOG_NOTICE, _("can't open %s for reading"), keyfile);
99
if (fstat(rfd, &statbuf) < 0) {
100
syslog(LOG_NOTICE, _("can't stat(%s)"), keyfile);
101
goto close_and_bail_out;
103
if ((statbuf.st_uid != pwd->pw_uid)
104
|| ((statbuf.st_mode & S_IFMT) != S_IFREG)
105
|| (statbuf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) {
106
syslog(LOG_NOTICE, _("%s doesn't have the correct filemodes"), keyfile);
107
goto close_and_bail_out;
110
if (read(rfd, key, 8) < 8) {
111
syslog(LOG_NOTICE, _("can't read data from %s"), keyfile);
112
goto close_and_bail_out;
129
check_response(char *challenge, char *response, char *key)
134
extern void des (union LR_block *);
135
extern void loadkey(char *,int);
136
extern void set_des_mode(int);
140
strncpy((char *)data.string, (char *)challenge, 8);
141
set_des_mode(ENCRYPT);
142
loadkey(key, NOSHIFT);
145
memset(key, 0, 8); /* no need for the secret key anymore, scratch it */
147
sprintf(buf, "%2.2X%2.2X%2.2X%2.2X",
148
(int)(data.LR[0]) & 0xff,
149
(int)(data.LR[0]>>8) & 0xff,
150
(int)(data.LR[0]>>16) & 0xff,
151
(int)(data.LR[0]>>24) & 0xff);
152
#endif /* KOONTZ_DES */
157
des_set_key((des_cblock *)key, ks);
159
des_ecb_encrypt((des_cblock *)challenge, &res, ks, DES_ENCRYPT);
162
/* use this on Intel x86 boxes */
163
sprintf(buf, "%2.2X%2.2X%2.2X%2.2X",
164
res[0], res[1], res[2], res[3]);
165
#else /* ie. BIG_ENDIAN */
166
/* use this on big endian RISC boxes */
167
sprintf(buf, "%2.2X%2.2X%2.2X%2.2X",
168
res[3], res[2], res[1], res[0]);
169
#endif /* LITTLE_ENDIAN */
170
#endif /* EAY_LIBDES */
172
/* return success only if ALL requirements have been met */
173
if (strncmp(buf, response, 8) == 0)
187
challenge = generate_challenge();
188
if (challenge == NULL) return 0;
190
if (strlen(challenge) + 13 > sizeof(prompt)) return 0;
191
sprintf(prompt, "%s Password: ", challenge);
193
alarm((unsigned int)timeout); /* give user time to fiddle with card */
194
response = getpass(prompt); /* presents challenge and gets response */
196
if (response == NULL) return 0;
198
/* This requires some explanation: As root we may not be able to
199
read the directory of the user if it is on an NFS mounted
200
filesystem. We temporarily set our effective uid to the user-uid
201
making sure that we keep root privs. in the real uid.
203
A portable solution would require a fork(), but we rely on Linux
204
having the BSD setreuid() */
207
uid_t ruid = getuid();
208
gid_t egid = getegid();
210
setregid(-1, pwd->pw_gid);
211
setreuid(0, pwd->pw_uid);
213
/* now we can access the file */
214
/* get the (properly qualified) key */
217
/* reset to root privs */
218
setuid(0); /* setreuid doesn't do it alone! */
222
if (key == NULL) return 0;
225
return check_response(challenge, response, key);
228
#endif /* CRYPTOCARD */