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