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