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