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