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