Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / kauth / client.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15 #include <afs/opr.h>
16
17 #include <hcrypto/des.h>
18 #include <hcrypto/ui.h>
19
20 #include <rx/rxkad_convert.h>
21
22 #include <afs/pthread_glock.h>
23 #include <afs/cellconfig.h>
24 #include <afs/auth.h>
25 #include <afs/afsutil.h>
26
27 #include "kauth.h"
28 #include "kautils.h"
29
30 /* This defines the Andrew string_to_key function. It accepts a password
31 string as input and converts it via a one-way encryption algorithm to a DES
32 encryption key. It is compatible with the original Andrew authentication
33 service password database. */
34
35 static void
36 Andrew_StringToKey(char *str, char *cell, /* cell for password */
37 struct ktc_encryptionKey *key)
38 {
39 char password[8 + 1]; /* crypt's limit is 8 chars anyway */
40 int i;
41 int passlen;
42
43 memset(key, 0, sizeof(struct ktc_encryptionKey));
44
45 strncpy(password, cell, 8);
46 passlen = strlen(str);
47 if (passlen > 8)
48 passlen = 8;
49
50 for (i = 0; i < passlen; i++)
51 password[i] ^= str[i];
52
53 for (i = 0; i < 8; i++)
54 if (password[i] == '\0')
55 password[i] = 'X';
56
57 /* crypt only considers the first 8 characters of password but for some
58 * reason returns eleven characters of result (plus the two salt chars). */
59 strncpy((char *)key, (char *)crypt(password, "p1") + 2,
60 sizeof(struct ktc_encryptionKey));
61
62 /* parity is inserted into the LSB so leftshift each byte up one bit. This
63 * allows ascii characters with a zero MSB to retain as much significance
64 * as possible. */
65 {
66 char *keybytes = (char *)key;
67 unsigned int temp;
68
69 for (i = 0; i < 8; i++) {
70 temp = (unsigned int)keybytes[i];
71 keybytes[i] = (unsigned char)(temp << 1);
72 }
73 }
74 DES_set_odd_parity(ktc_to_cblock(key));
75 }
76
77 static void
78 StringToKey(char *str, char *cell, /* cell for password */
79 struct ktc_encryptionKey *key)
80 {
81 DES_key_schedule schedule;
82 DES_cblock temp_key;
83 DES_cblock ivec;
84 char password[BUFSIZ];
85 int passlen;
86
87 strncpy(password, str, sizeof(password));
88 if ((passlen = strlen(password)) < sizeof(password) - 1)
89 strncat(password, cell, sizeof(password) - passlen);
90 if ((passlen = strlen(password)) > sizeof(password))
91 passlen = sizeof(password);
92
93 memcpy(&ivec, "kerberos", 8);
94 memcpy(&temp_key, "kerberos", 8);
95 DES_set_odd_parity(&temp_key);
96 DES_key_sched(&temp_key, &schedule);
97 DES_cbc_cksum((DES_cblock *) password, &ivec, passlen, &schedule, &ivec);
98
99 memcpy(&temp_key, &ivec, 8);
100 DES_set_odd_parity(&temp_key);
101 DES_key_sched(&temp_key, &schedule);
102 DES_cbc_cksum((DES_cblock *)password, ktc_to_cblock(key), passlen,
103 &schedule, &ivec);
104
105 DES_set_odd_parity(ktc_to_cblock(key));
106 }
107
108 void
109 ka_StringToKey(char *str, char *cell, /* cell for password */
110 struct ktc_encryptionKey *key)
111 {
112 char realm[MAXKTCREALMLEN];
113 afs_int32 code;
114
115 LOCK_GLOBAL_MUTEX;
116 code = ka_CellToRealm(cell, realm, 0 /*local */ );
117 if (code) /* just take his word for it */
118 strncpy(realm, cell, sizeof(realm));
119 else /* for backward compatibility */
120 lcstring(realm, realm, sizeof(realm));
121 if (strlen(str) > 8)
122 StringToKey(str, realm, key);
123 else
124 Andrew_StringToKey(str, realm, key);
125 UNLOCK_GLOBAL_MUTEX;
126 }
127
128 /* This prints out a prompt and reads a string from the terminal, turning off
129 echoing. If verify is requested it requests that the string be entered
130 again and the two strings are compared. The string is then converted to a
131 DES encryption key. */
132
133 /* Errors:
134 KAREADPW - some error returned from read_pw_string
135 */
136
137 afs_int32
138 ka_ReadPassword(char *prompt, int verify, char *cell,
139 struct ktc_encryptionKey *key)
140 {
141 char password[BUFSIZ];
142 afs_int32 code;
143
144 LOCK_GLOBAL_MUTEX;
145 memset(key, 0, sizeof(struct ktc_encryptionKey));
146 code = UI_UTIL_read_pw_string(password, sizeof(password), prompt, verify);
147 if (code) {
148 UNLOCK_GLOBAL_MUTEX;
149 return KAREADPW;
150 }
151 if (strlen(password) == 0) {
152 UNLOCK_GLOBAL_MUTEX;
153 return KANULLPASSWORD;
154 }
155 ka_StringToKey(password, cell, key);
156 UNLOCK_GLOBAL_MUTEX;
157 return 0;
158 }
159
160 /* This performs the backslash quoting defined by AC_ParseLoginName. */
161
162 static char
163 map_char(char *str, int *ip)
164 {
165 char c = str[*ip];
166 if (c == '\\') {
167 c = str[++(*ip)];
168 if ((c >= '0') && (c <= '7')) {
169 c = c - '0';
170 c = (c * 8) + (str[++(*ip)] - '0');
171 c = (c * 8) + (str[++(*ip)] - '0');
172 }
173 }
174 return c;
175 }
176
177 /* This routine parses a string that might be entered by a user from the
178 terminal. It defines a syntax to allow a user to specify his identity in
179 terms of his name, instance and cell with a single string. These three
180 output strings must be allocated by the caller to their maximum length. The
181 syntax is very simple: the first dot ('.') separates the name from the
182 instance and the first atsign ('@') begins the cell name. A backslash ('\')
183 can be used to quote these special characters. A backslash followed by an
184 octal digit (zero through seven) introduces a three digit octal number which
185 is interpreted as the ascii value of a single character. */
186
187 /* Errors:
188 KABADARGUMENT - if no output parameters are specified.
189 KABADNAME - if a component of the user name is too long or if a cell was
190 specified but the cell parameter was null.
191 */
192
193 afs_int32
194 ka_ParseLoginName(char *login, char name[MAXKTCNAMELEN],
195 char inst[MAXKTCNAMELEN], char cell[MAXKTCREALMLEN])
196 {
197 int login_len = strlen(login);
198 char rc, c;
199 int i, j;
200 #define READNAME 1
201 #define READINST 2
202 #define READCELL 3
203 int reading;
204
205 if (!name)
206 return KABADARGUMENT;
207 strcpy(name, "");
208 if (inst)
209 strcpy(inst, "");
210 if (cell)
211 strcpy(cell, "");
212 reading = READNAME;
213 i = 0;
214 j = 0;
215 while (i < login_len) {
216 rc = login[i];
217 c = map_char(login, &i);
218 switch (reading) {
219 case READNAME:
220 if (rc == '@') {
221 name[j] = 0; /* finish name */
222 reading = READCELL; /* but instance is null */
223 j = 0;
224 break;
225 }
226 if (inst && (rc == '.')) {
227 name[j] = 0; /* finish name */
228 reading = READINST;
229 j = 0;
230 break;
231 }
232 if (j >= MAXKTCNAMELEN - 1)
233 return KABADNAME;
234 name[j++] = c;
235 break;
236 case READINST:
237 if (!inst)
238 return KABADNAME;
239 if (rc == '@') {
240 inst[j] = 0; /* finish name */
241 reading = READCELL;
242 j = 0;
243 break;
244 }
245 if (j >= MAXKTCNAMELEN - 1)
246 return KABADNAME;
247 inst[j++] = c;
248 break;
249 case READCELL:
250 if (!cell)
251 return KABADNAME;
252 if (j >= MAXKTCREALMLEN - 1)
253 return KABADNAME;
254 cell[j++] = c;
255 break;
256 }
257 i++;
258 }
259 if (reading == READNAME)
260 name[j] = 0;
261 else if (reading == READINST) {
262 if (inst)
263 inst[j] = 0;
264 else
265 return KABADNAME;
266 } else if (reading == READCELL) {
267 if (cell)
268 cell[j] = 0;
269 else
270 return KABADNAME;
271 }
272
273 /* the cell is really an authDomain and therefore is really a realm */
274 if (cell)
275 ucstring(cell, cell, MAXKTCREALMLEN);
276 return 0;
277 }
278
279 /* Client side applications should call this to initialize error tables and
280 connect to the correct CellServDB file. */
281
282 afs_int32
283 ka_Init(int flags)
284 { /* reserved for future use. */
285 afs_int32 code;
286 static int inited = 0;
287
288 LOCK_GLOBAL_MUTEX;
289 if (inited) {
290 UNLOCK_GLOBAL_MUTEX;
291 return 0;
292 }
293 inited++;
294 initialize_U_error_table();
295 initialize_KA_error_table();
296 initialize_RXK_error_table();
297 initialize_KTC_error_table();
298 initialize_ACFG_error_table();
299 code = ka_CellConfig(AFSDIR_CLIENT_ETC_DIRPATH);
300 UNLOCK_GLOBAL_MUTEX;
301 if (code)
302 return code;
303 return 0;
304 }
305
306 #ifdef MAIN
307 int
308 main(void)
309 {
310 struct ktc_encryptionKey key;
311 int code;
312 char line[256];
313 char name[MAXKTCNAMELEN];
314 char instance[MAXKTCNAMELEN];
315 char cell[MAXKTCREALMLEN];
316
317 printf("Enter login:");
318 fgets(line, 255, stdin);
319 ka_ParseLoginName(line, name, instance, cell);
320 printf("'%s' '%s' '%s'\n", name, instance, cell);
321
322 }
323 #endif /* MAIN */