reindent-20030715
[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 code = ka_CellToRealm(cell, realm, 0 /*local */ );
145     if (code)                   /* just take his word for it */
146         strncpy(realm, cell, sizeof(realm));
147     else                        /* for backward compatibility */
148         lcstring(realm, realm, sizeof(realm));
149     if (strlen(str) > 8)
150         StringToKey(str, realm, key);
151     else
152         Andrew_StringToKey(str, realm, key);
153 UNLOCK_GLOBAL_MUTEX}
154
155 /* This prints out a prompt and reads a string from the terminal, turning off
156    echoing.  If verify is requested it requests that the string be entered
157    again and the two strings are compared.  The string is then converted to a
158    DES encryption key. */
159
160 /* Errors:
161      KAREADPW - some error returned from read_pw_string
162  */
163
164 afs_int32
165 ka_ReadPassword(char *prompt, int verify, char *cell,
166                 struct ktc_encryptionKey *key)
167 {
168     char password[BUFSIZ];
169     afs_int32 code;
170
171     LOCK_GLOBAL_MUTEX memset(key, 0, sizeof(struct ktc_encryptionKey));
172     code = read_pw_string(password, sizeof(password), prompt, verify);
173     if (code) {
174         UNLOCK_GLOBAL_MUTEX return KAREADPW;
175     }
176     if (strlen(password) == 0) {
177         UNLOCK_GLOBAL_MUTEX return KANULLPASSWORD;
178     }
179     ka_StringToKey(password, cell, key);
180     UNLOCK_GLOBAL_MUTEX return 0;
181 }
182
183 /* This performs the backslash quoting defined by AC_ParseLoginName. */
184
185 static char
186 map_char(str, ip)
187      char *str;
188      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 if (inited) {
314         UNLOCK_GLOBAL_MUTEX return 0;
315     }
316     inited++;
317     initialize_U_error_table();
318     initialize_KA_error_table();
319     initialize_RXK_error_table();
320     initialize_KTC_error_table();
321     initialize_ACFG_error_table();
322     code = ka_CellConfig(AFSDIR_CLIENT_ETC_DIRPATH);
323     UNLOCK_GLOBAL_MUTEX if (code)
324           return code;
325     return 0;
326 }
327
328 #ifdef MAIN
329 int
330 main(void)
331 {
332     struct ktc_encryptionKey key;
333     int code;
334     char line[256];
335     char name[MAXKTCNAMELEN];
336     char instance[MAXKTCNAMELEN];
337     char cell[MAXKTCREALMLEN];
338
339     printf("Enter login:");
340     fgets(line, 255, stdin);
341     ka_ParseLoginName(line, name, instance, cell);
342     printf("'%s' '%s' '%s'\n", name, instance, cell);
343
344 }
345 #endif /* MAIN */