Prototype kalog_Init
[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/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 #if !defined(__USE_XOPEN)
46 #define __USE_XOPEN
47 #endif
48 #include <unistd.h>
49 #endif
50 #include <afs/cellconfig.h>
51 #include <afs/auth.h>
52 #include <afs/afsutil.h>
53 #include <des.h>
54 #include <des_prototypes.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(ktc_to_cblock(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     unsigned 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(charptr_to_cblockptr(password), charptr_to_cblockptr(ivec), passlen, schedule, charptr_to_cblockptr(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(charptr_to_cblockptr(password), ktc_to_cblockptr(key), passlen, schedule, charptr_to_cblockptr(ivec));
133
134     des_fixup_key_parity(ktc_to_cblock(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(char *str, int *ip)
193 {
194     char c = str[*ip];
195     if (c == '\\') {
196         c = str[++(*ip)];
197         if ((c >= '0') && (c <= '7')) {
198             c = c - '0';
199             c = (c * 8) + (str[++(*ip)] - '0');
200             c = (c * 8) + (str[++(*ip)] - '0');
201         }
202     }
203     return c;
204 }
205
206 /* This routine parses a string that might be entered by a user from the
207    terminal.  It defines a syntax to allow a user to specify his identity in
208    terms of his name, instance and cell with a single string.  These three
209    output strings must be allocated by the caller to their maximum length.  The
210    syntax is very simple: the first dot ('.') separates the name from the
211    instance and the first atsign ('@') begins the cell name.  A backslash ('\')
212    can be used to quote these special characters.  A backslash followed by an
213    octal digit (zero through seven) introduces a three digit octal number which
214    is interpreted as the ascii value of a single character. */
215
216 /* Errors:
217      KABADARGUMENT - if no output parameters are specified.
218      KABADNAME - if a component of the user name is too long or if a cell was
219        specified but the cell parameter was null.
220  */
221
222 afs_int32
223 ka_ParseLoginName(char *login, char name[MAXKTCNAMELEN],
224                   char inst[MAXKTCNAMELEN], char cell[MAXKTCREALMLEN])
225 {
226     int login_len = strlen(login);
227     char rc, c;
228     int i, j;
229 #define READNAME 1
230 #define READINST 2
231 #define READCELL 3
232     int reading;
233
234     if (!name)
235         return KABADARGUMENT;
236     strcpy(name, "");
237     if (inst)
238         strcpy(inst, "");
239     if (cell)
240         strcpy(cell, "");
241     reading = READNAME;
242     i = 0;
243     j = 0;
244     while (i < login_len) {
245         rc = login[i];
246         c = map_char(login, &i);
247         switch (reading) {
248         case READNAME:
249             if (rc == '@') {
250                 name[j] = 0;    /* finish name */
251                 reading = READCELL;     /* but instance is null */
252                 j = 0;
253                 break;
254             }
255             if (inst && (rc == '.')) {
256                 name[j] = 0;    /* finish name */
257                 reading = READINST;
258                 j = 0;
259                 break;
260             }
261             if (j >= MAXKTCNAMELEN - 1)
262                 return KABADNAME;
263             name[j++] = c;
264             break;
265         case READINST:
266             if (!inst)
267                 return KABADNAME;
268             if (rc == '@') {
269                 inst[j] = 0;    /* finish name */
270                 reading = READCELL;
271                 j = 0;
272                 break;
273             }
274             if (j >= MAXKTCNAMELEN - 1)
275                 return KABADNAME;
276             inst[j++] = c;
277             break;
278         case READCELL:
279             if (!cell)
280                 return KABADNAME;
281             if (j >= MAXKTCREALMLEN - 1)
282                 return KABADNAME;
283             cell[j++] = c;
284             break;
285         }
286         i++;
287     }
288     if (reading == READNAME)
289         name[j] = 0;
290     else if (reading == READINST) {
291         if (inst)
292             inst[j] = 0;
293         else
294             return KABADNAME;
295     } else if (reading == READCELL) {
296         if (cell)
297             cell[j] = 0;
298         else
299             return KABADNAME;
300     }
301
302     /* the cell is really an authDomain and therefore is really a realm */
303     if (cell)
304         ucstring(cell, cell, MAXKTCREALMLEN);
305     return 0;
306 }
307
308 /* Client side applications should call this to initialize error tables and
309    connect to the correct CellServDB file. */
310
311 afs_int32
312 ka_Init(int flags)
313 {                               /* reserved for future use. */
314     afs_int32 code;
315     static int inited = 0;
316
317     LOCK_GLOBAL_MUTEX;
318     if (inited) {
319         UNLOCK_GLOBAL_MUTEX;
320         return 0;
321     }
322     inited++;
323     initialize_U_error_table();
324     initialize_KA_error_table();
325     initialize_RXK_error_table();
326     initialize_KTC_error_table();
327     initialize_ACFG_error_table();
328     code = ka_CellConfig(AFSDIR_CLIENT_ETC_DIRPATH);
329     UNLOCK_GLOBAL_MUTEX;
330     if (code)
331         return code;
332     return 0;
333 }
334
335 #ifdef MAIN
336 int
337 main(void)
338 {
339     struct ktc_encryptionKey key;
340     int code;
341     char line[256];
342     char name[MAXKTCNAMELEN];
343     char instance[MAXKTCNAMELEN];
344     char cell[MAXKTCREALMLEN];
345
346     printf("Enter login:");
347     fgets(line, 255, stdin);
348     ka_ParseLoginName(line, name, instance, cell);
349     printf("'%s' '%s' '%s'\n", name, instance, cell);
350
351 }
352 #endif /* MAIN */