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