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