]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/cryptocard.c
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@misiek.eu.org>
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 */