Commit | Line | Data |
---|---|---|
805e021f CE |
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 */ |