]> git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/cryptocard.c
Imported from util-linux-2.10s tarball.
[thirdparty/util-linux.git] / 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
7 can be found in:
8
9 ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/des/
10
11 (Link with the fdes.o file from that distribution)
12
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.
15
16 The sources for this code are maintained in
17
18 ftp://ftp.daimi.aau.dk/pub/linux/poe/poeigl-X.XX.tar.gz
19
20 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
21 - added Native Language Support
22
23 */
24 #ifdef CRYPTOCARD
25
26 /******************** CONFIGURATION section *****************************/
27 /*--------------- select ONE DES implementation ------------------------*/
28 /*#define KOONTZ_DES */
29 #define EAY_LIBDES
30 /*--------------- define if on little endian machine (Intel x86) -------*/
31 #define LITTLE_ENDIAN
32 /******************** end of CONFIGURATION section **********************/
33
34 #define _BSD_SOURCE
35 #define _GNU_SOURCE
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stddef.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <syslog.h>
44 #include <pwd.h>
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #include "nls.h"
48
49 #ifdef KOONTZ_DES
50 #include "../koontz-des/des.h"
51 #endif /* KOONTZ_DES */
52
53 #ifdef EAY_LIBDES
54 #include "../libdes/des.h"
55 #endif /* EAY_LIBDES */
56
57 #include "cryptocard.h"
58
59 static char *
60 generate_challenge(void)
61 {
62 static char challenge_str[30];
63 int rfd;
64 unsigned long clong;
65
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"));
69 return NULL;
70 }
71 if (read(rfd, &clong, 4) < 4) {
72 close(rfd);
73 syslog(LOG_NOTICE, _("couldn't read random data from /dev/urandom"));
74 return NULL;
75 }
76 close(rfd);
77
78 sprintf(challenge_str,"%08lu", clong);
79 return challenge_str;
80 }
81
82 static char *
83 get_key()
84 {
85 int success = 0;
86 char keyfile[MAXPATHLEN];
87 static char key[10];
88 int rfd;
89 struct stat statbuf;
90
91 if (strlen(pwd->pw_dir) + 13 > sizeof(keyfile))
92 goto bail_out;
93 sprintf(keyfile, "%s/.cryptocard", pwd->pw_dir);
94
95 if ((rfd = open(keyfile, O_RDONLY)) < 0) {
96 syslog(LOG_NOTICE, _("can't open %s for reading"), keyfile);
97 goto bail_out;
98 }
99 if (fstat(rfd, &statbuf) < 0) {
100 syslog(LOG_NOTICE, _("can't stat(%s)"), keyfile);
101 goto close_and_bail_out;
102 }
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;
108 }
109
110 if (read(rfd, key, 8) < 8) {
111 syslog(LOG_NOTICE, _("can't read data from %s"), keyfile);
112 goto close_and_bail_out;
113 }
114
115 key[8] = 0;
116 success = 1;
117
118 close_and_bail_out:
119 close(rfd);
120
121 bail_out:
122 if (success)
123 return key;
124 else
125 return NULL;
126 }
127
128 static int
129 check_response(char *challenge, char *response, char *key)
130 {
131 char buf[20];
132
133 #ifdef KOONTZ_DES
134 extern void des (union LR_block *);
135 extern void loadkey(char *,int);
136 extern void set_des_mode(int);
137
138 union LR_block data;
139
140 strncpy((char *)data.string, (char *)challenge, 8);
141 set_des_mode(ENCRYPT);
142 loadkey(key, NOSHIFT);
143 des(&data);
144
145 memset(key, 0, 8); /* no need for the secret key anymore, scratch it */
146
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 */
153 #ifdef EAY_LIBDES
154 des_cblock res;
155 des_key_schedule ks;
156
157 des_set_key((des_cblock *)key, ks);
158 memset(key, 0, 8);
159 des_ecb_encrypt((des_cblock *)challenge, &res, ks, DES_ENCRYPT);
160
161 #ifdef LITTLE_ENDIAN
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 */
171
172 /* return success only if ALL requirements have been met */
173 if (strncmp(buf, response, 8) == 0)
174 return 1;
175
176 return 0;
177 }
178
179 int
180 cryptocard(void)
181 {
182 char prompt[80];
183 char *challenge;
184 char *key;
185 char *response;
186
187 challenge = generate_challenge();
188 if (challenge == NULL) return 0;
189
190 if (strlen(challenge) + 13 > sizeof(prompt)) return 0;
191 sprintf(prompt, "%s Password: ", challenge);
192
193 alarm((unsigned int)timeout); /* give user time to fiddle with card */
194 response = getpass(prompt); /* presents challenge and gets response */
195
196 if (response == NULL) return 0;
197
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.
202
203 A portable solution would require a fork(), but we rely on Linux
204 having the BSD setreuid() */
205
206 {
207 uid_t ruid = getuid();
208 gid_t egid = getegid();
209
210 setregid(-1, pwd->pw_gid);
211 setreuid(0, pwd->pw_uid);
212
213 /* now we can access the file */
214 /* get the (properly qualified) key */
215 key = get_key();
216
217 /* reset to root privs */
218 setuid(0); /* setreuid doesn't do it alone! */
219 setreuid(ruid, 0);
220 setregid(-1, egid);
221
222 if (key == NULL) return 0;
223 }
224
225 return check_response(challenge, response, key);
226 }
227
228 #endif /* CRYPTOCARD */