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