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