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