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