2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* This code borrows from nsafs.c - slightly modified - names,etc. */
12 #include <afsconfig.h>
13 #include <afs/param.h>
16 #include "apache_afs_cache.h"
19 * Value used to initialize SHA checksums on username/password pairs
21 afs_uint32 weblog_login_pad
[SHA_HASH_INTS
] = {
22 0x0D544971, 0x2281AC5B, 0x58B51218, 0x4085E08D, 0xB68C484B
29 struct weblog_login
*head
;
30 struct weblog_login
*tail
;
31 } weblog_login_cache
[WEBLOG_LOGIN_HASH_SIZE
];
33 /* shchecksum.c copied here */
36 * This module implements the Secure Hash Algorithm (SHA) as specified in
37 * the Secure Hash Standard (SHS, FIPS PUB 180.1).
40 static int big_endian
;
42 static const sha_int hashinit
[] = {
43 0x67452301, 0xEFCDAB89, 0x98BADCFE,
44 0x10325476, 0xC3D2E1F0
47 #define ROTL(n, x) (((x) << (n)) | ((x) >> (SHA_BITS_PER_INT - (n))))
49 #ifdef DISABLED_CODE_HERE
51 f(int t
, sha_int x
, sha_int y
, sha_int z
)
53 if (t
< 0 || t
>= SHA_ROUNDS
)
56 return (z
^ (x
& (y
^ z
)));
60 return ((x
& y
) | (z
& (x
| y
))); /* saves 1 boolean op */
61 return (x
^ y
^ z
); /* 60-79 same as 40-59 */
65 /* This is the "magic" function used for each round. */
66 /* Were this a C function, the interface would be: */
67 /* static sha_int f(int t, sha_int x, sha_int y, sha_int z) */
68 /* The function call version preserved above until stable */
70 #define f_a(x, y, z) (z ^ (x & (y ^ z)))
71 #define f_b(x, y, z) (x ^ y ^ z)
72 #define f_c(x, y, z) (( (x & y) | (z & (x | y))))
74 #define f(t, x, y, z) \
75 ( (t < 0 || t >= SHA_ROUNDS) ? 0 : \
76 ( (t < 20) ? f_a(x, y, z) : \
77 ( (t < 40) ? f_b(x, y, z) : \
78 ( (t < 60) ? f_c(x, y, z) : f_b(x, y, z)))))
81 *static sha_int K(int t)
83 * if (t < 0 || t >= SHA_ROUNDS) return 0;
94 /* This macro/function supplies the "magic" constant for each round. */
95 /* The function call version preserved above until stable */
97 static const sha_int k_vals
[] =
98 { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
100 #define K(t) ( (t < 0 || t >= SHA_ROUNDS) ? 0 : k_vals[ t/20 ] )
103 * Update the internal state based on the given chunk.
106 transform(shaState
* shaStateP
, sha_int
* chunk
)
108 sha_int A
= shaStateP
->digest
[0];
109 sha_int B
= shaStateP
->digest
[1];
110 sha_int C
= shaStateP
->digest
[2];
111 sha_int D
= shaStateP
->digest
[3];
112 sha_int E
= shaStateP
->digest
[4];
116 sha_int W
[SHA_ROUNDS
];
118 for (t
= 0; t
< SHA_CHUNK_INTS
; t
++)
120 for (; t
< SHA_ROUNDS
; t
++) {
121 TEMP
= W
[t
- 3] ^ W
[t
- 8] ^ W
[t
- 14] ^ W
[t
- 16];
122 W
[t
] = ROTL(1, TEMP
);
125 for (t
= 0; t
< SHA_ROUNDS
; t
++) {
126 TEMP
= ROTL(5, A
) + f(t
, B
, C
, D
) + E
+ W
[t
] + K(t
);
134 shaStateP
->digest
[0] += A
;
135 shaStateP
->digest
[1] += B
;
136 shaStateP
->digest
[2] += C
;
137 shaStateP
->digest
[3] += D
;
138 shaStateP
->digest
[4] += E
;
143 * This function takes an array of SHA_CHUNK_BYTES bytes
144 * as input and produces an output array of ints that is
145 * SHA_CHUNK_INTS long.
148 buildInts(const char *data
, sha_int
* chunk
)
151 * Need to copy the data because we can't be certain that
152 * the input buffer will be aligned correctly.
154 memcpy((void *)chunk
, (void *)data
, SHA_CHUNK_BYTES
);
157 /* This loop does nothing but waste time on a big endian machine. */
160 for (i
= 0; i
< SHA_CHUNK_INTS
; i
++)
161 chunk
[i
] = ntohl(chunk
[i
]);
166 * This function updates the internal state of the hash by using
167 * buildInts to break the input up into chunks and repeatedly passing
168 * these chunks to transform().
171 sha_update(shaState
* shaStateP
, const char *buffer
, int bufferLen
)
174 sha_int chunk
[SHA_CHUNK_INTS
];
177 if (buffer
== NULL
|| bufferLen
== 0)
180 newLo
= shaStateP
->bitcountLo
+ (bufferLen
<< 3);
181 if (newLo
< shaStateP
->bitcountLo
)
182 shaStateP
->bitcountHi
++;
183 shaStateP
->bitcountLo
= newLo
;
184 shaStateP
->bitcountHi
+= ((bufferLen
>> (SHA_BITS_PER_INT
- 3)) & 0x07);
187 * If we won't have enough for a full chunk, just tack this
188 * buffer onto the leftover piece and return.
190 if (shaStateP
->leftoverLen
+ bufferLen
< SHA_CHUNK_BYTES
) {
191 memcpy((void *)&(shaStateP
->leftover
[shaStateP
->leftoverLen
]),
192 (void *)buffer
, bufferLen
);
193 shaStateP
->leftoverLen
+= bufferLen
;
197 /* If we have a leftover chunk, process it first. */
198 if (shaStateP
->leftoverLen
> 0) {
199 i
= (SHA_CHUNK_BYTES
- shaStateP
->leftoverLen
);
200 memcpy((void *)&(shaStateP
->leftover
[shaStateP
->leftoverLen
]),
204 buildInts(shaStateP
->leftover
, chunk
);
205 shaStateP
->leftoverLen
= 0;
206 transform(shaStateP
, chunk
);
209 while (bufferLen
>= SHA_CHUNK_BYTES
) {
210 buildInts(buffer
, chunk
);
211 transform(shaStateP
, chunk
);
212 buffer
+= SHA_CHUNK_BYTES
;
213 bufferLen
-= SHA_CHUNK_BYTES
;
215 /* assert((bufferLen >= 0) && (bufferLen < SHA_CHUNK_BYTES)); */
216 if ((bufferLen
< 0) || (bufferLen
> SHA_CHUNK_BYTES
)) {
217 fprintf(stderr
, "apache_afs_cache: ASSERTION FAILED...exiting\n");
222 memcpy((void *)&shaStateP
->leftover
[0], (void *)buffer
, bufferLen
);
223 shaStateP
->leftoverLen
= bufferLen
;
229 * This method updates the internal state of the hash using
230 * any leftover data plus appropriate padding and incorporation
231 * of the hash bitcount to finish the hash. The hash value
232 * is not valid until finish() has been called.
235 sha_finish(shaState
* shaStateP
)
237 sha_int chunk
[SHA_CHUNK_INTS
];
240 if (shaStateP
->leftoverLen
> (SHA_CHUNK_BYTES
- 9)) {
241 shaStateP
->leftover
[shaStateP
->leftoverLen
++] = 0x80;
242 memset(&(shaStateP
->leftover
[shaStateP
->leftoverLen
]), 0,
243 (SHA_CHUNK_BYTES
- shaStateP
->leftoverLen
));
244 buildInts(shaStateP
->leftover
, chunk
);
245 transform(shaStateP
, chunk
);
246 memset(chunk
, 0, SHA_CHUNK_BYTES
);
248 shaStateP
->leftover
[shaStateP
->leftoverLen
++] = 0x80;
249 memset(&(shaStateP
->leftover
[shaStateP
->leftoverLen
]), 0,
250 (SHA_CHUNK_BYTES
- shaStateP
->leftoverLen
));
251 buildInts(shaStateP
->leftover
, chunk
);
253 shaStateP
->leftoverLen
= 0;
255 chunk
[SHA_CHUNK_INTS
- 2] = shaStateP
->bitcountHi
;
256 chunk
[SHA_CHUNK_INTS
- 1] = shaStateP
->bitcountLo
;
257 transform(shaStateP
, chunk
);
262 * Initialize the hash to its "magic" initial value specified by the
263 * SHS standard, and clear out the bitcount and leftover vars.
264 * This should be used to initialize an shaState.
267 sha_clear(shaState
* shaStateP
)
269 big_endian
= (0x01020304 == htonl(0x01020304));
271 memcpy((void *)&shaStateP
->digest
[0], (void *)&hashinit
[0],
273 shaStateP
->bitcountLo
= shaStateP
->bitcountHi
= 0;
274 shaStateP
->leftoverLen
= 0;
279 * Hash the buffer and place the result in *shaStateP.
282 sha_hash(shaState
* shaStateP
, const char *buffer
, int bufferLen
)
284 sha_clear(shaStateP
);
285 sha_update(shaStateP
, buffer
, bufferLen
);
286 sha_finish(shaStateP
);
291 * Returns the current state of the hash as an array of 20 bytes.
292 * This will be an interim result if finish() has not yet been called.
295 sha_bytes(const shaState
* shaStateP
, char *bytes
)
297 sha_int temp
[SHA_HASH_INTS
];
300 for (i
= 0; i
< SHA_HASH_INTS
; i
++)
301 temp
[i
] = htonl(shaStateP
->digest
[i
]);
302 memcpy(bytes
, (void *)&temp
[0], SHA_HASH_BYTES
);
307 * Hash function for the AFS login cache
310 weblog_login_hash(char *name
, char *cell
)
314 for (val
= *name
, p
= name
; *p
!= '\0'; p
++) {
315 val
= (val
<< 2) ^ val
^ (afs_uint32
) (*p
);
317 for (p
= cell
; *p
!= '\0'; p
++) {
318 val
= (val
<< 2) ^ val
^ (afs_uint32
) (*p
);
320 return val
& (WEBLOG_LOGIN_HASH_SIZE
- 1);
324 * Compute a SHA checksum on the username, cellname, and password
327 weblog_login_checksum(char *user
, char *cell
, char *passwd
, char *cksum
)
336 * Compute SHA(username,SHA(password,pad))
338 passwdLen
= strlen(passwd
);
339 userLen
= strlen(user
);
340 cellLen
= strlen(cell
);
342 (char *)malloc(MAX(userLen
+ cellLen
, passwdLen
) + SHA_HASH_BYTES
);
343 strcpy(shaBuffer
, passwd
);
344 memcpy((void *)(shaBuffer
+ passwdLen
), (void *)(&weblog_login_pad
[0]),
347 sha_hash(&state
, shaBuffer
, passwdLen
+ SHA_HASH_BYTES
);
348 memcpy(shaBuffer
, user
, userLen
);
349 memcpy(shaBuffer
+ userLen
, cell
, cellLen
);
350 sha_bytes(&state
, shaBuffer
+ userLen
+ cellLen
);
352 sha_hash(&state
, shaBuffer
, userLen
+ cellLen
+ SHA_HASH_BYTES
);
353 sha_bytes(&state
, &cksum
[0]);
354 memset(shaBuffer
, 0, MAX(userLen
+ cellLen
, passwdLen
) + SHA_HASH_BYTES
);
359 * Look up a login ID in the cache. If an entry name is found for the
360 * given username, and the SHA checksums match, then
361 * set the token parameter and return 1, otherwise return 0.
364 weblog_login_lookup(char *user
, char *cell
, char *cksum
, char *token
)
368 struct weblog_login
*loginP
, *tmpP
, loginTmp
;
371 * Search the hash chain for a matching entry, free
372 * expired entries as we search
374 index
= weblog_login_hash(user
, cell
);
375 curTime
= time(NULL
);
377 loginP
= weblog_login_cache
[index
].head
;
378 while (loginP
!= NULL
) {
379 if (loginP
->expiration
< curTime
) {
383 DLL_DELETE(tmpP
, weblog_login_cache
[index
].head
,
384 weblog_login_cache
[index
].tail
, next
, prev
);
388 if (strcmp(loginP
->username
, user
) == 0
389 && strcmp(loginP
->cellname
, cell
) == 0
390 && memcmp((void *)&loginP
->cksum
[0], (void *)cksum
,
391 SHA_HASH_BYTES
) == 0) {
393 memcpy((void *)token
, (void *)&loginP
->token
[0], MAXBUFF
);
394 return loginP
->tokenLen
;
396 loginP
= loginP
->next
;
402 * Insert a login token into the cache. If the user already has an entry,
403 * then overwrite the old entry.
406 weblog_login_store(char *user
, char *cell
, char *cksum
, char *token
,
407 int tokenLen
, afs_uint32 expiration
)
411 struct weblog_login
*loginP
, *tmpP
, loginTmp
;
413 int parseToken(char *tokenBuf
);
416 * Search the hash chain for a matching entry, free
417 * expired entries as we search
419 index
= weblog_login_hash(user
, cell
);
420 curTime
= time(NULL
);
421 loginP
= weblog_login_cache
[index
].head
;
423 while (loginP
!= NULL
) {
424 if (strcmp(loginP
->username
, user
) == 0
425 && strcmp(loginP
->cellname
, cell
) == 0) {
428 if (loginP
->expiration
< curTime
) {
432 DLL_DELETE(tmpP
, weblog_login_cache
[index
].head
,
433 weblog_login_cache
[index
].tail
, next
, prev
);
437 loginP
= loginP
->next
;
439 if (loginP
== NULL
) {
440 loginP
= (struct weblog_login
*)malloc(sizeof(struct weblog_login
));
441 strcpy(&loginP
->username
[0], user
);
442 strcpy(&loginP
->cellname
[0], cell
);
444 DLL_DELETE(loginP
, weblog_login_cache
[index
].head
,
445 weblog_login_cache
[index
].tail
, next
, prev
);
448 memcpy((void *)&loginP
->cksum
[0], (void *)cksum
, SHA_HASH_BYTES
);
449 loginP
->expiration
= expiration
;
450 loginP
->tokenLen
= getTokenLen(token
);
451 memcpy((void *)&loginP
->token
[0], (void *)token
, MAXBUFF
);
453 DLL_INSERT_TAIL(loginP
, weblog_login_cache
[index
].head
,
454 weblog_login_cache
[index
].tail
, next
, prev
);
461 for (i
= 0; i
< WEBLOG_LOGIN_HASH_SIZE
; i
++) {
462 DLL_INIT_LIST(weblog_login_cache
[i
].head
, weblog_login_cache
[i
].tail
);
467 getTokenLen(char *buf
)
471 char cellName
[WEBLOG_CELLNAME_MAX
];
473 int n
= sizeof(afs_int32
);
475 afs_int32 AuthHandle
;
476 char HandShakeKey
[8];
478 afs_int32 BeginTimestamp
;
479 afs_int32 EndTimestamp
;
482 memcpy(&len
, tp
, sizeof(afs_int32
)); /* get size of secret token */
483 rc
= (len
+ sizeof(afs_int32
));
484 tp
+= (sizeof(afs_int32
) + len
); /* skip secret token and its length */
485 memcpy(&len
, tp
, sizeof(afs_int32
)); /* get size of clear token */
486 if (len
!= sizeof(struct ClearToken
)) {
489 "apache_afs_cache.c:getExpiration:"
490 "something's wrong with the length of ClearToken:%d\n", len
);
494 rc
+= (sizeof(afs_int32
) + len
); /* length of clear token + length itself */
495 tp
+= (sizeof(afs_int32
) + len
); /* skip clear token and its length */
496 rc
+= sizeof(afs_int32
); /* length of primary flag */
497 tp
+= sizeof(afs_int32
); /* skip over primary flag */
498 strcpy(cellName
, tp
);
499 if (cellName
!= NULL
)
500 rc
+= strlen(cellName
);
505 getExpiration(char *buf
)
509 int n
= sizeof(afs_int32
);
511 afs_int32 AuthHandle
;
512 char HandShakeKey
[8];
514 afs_int32 BeginTimestamp
;
515 afs_int32 EndTimestamp
;
519 memcpy(&len
, tp
, sizeof(afs_int32
)); /* get size of secret token */
520 tp
+= (sizeof(afs_int32
) + len
); /* skip secret token and its length */
521 memcpy(&len
, tp
, sizeof(afs_int32
)); /* get size of clear token */
522 if (len
!= sizeof(struct ClearToken
)) {
525 "apache_afs_cache.c:getExpiration:"
526 "something's wrong with the length of ClearToken:%d\n", len
);
531 tp
+= sizeof(afs_int32
); /* skip length of clear token */
532 memcpy(&token
, tp
, sizeof(struct ClearToken
)); /* copy the token */
533 return token
.EndTimestamp
;