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>
18 #include "apache_afs_cache.h"
21 * Value used to initialize SHA checksums on username/password pairs
23 afs_uint32 weblog_login_pad[SHA_HASH_INTS] = {
24 0x0D544971, 0x2281AC5B, 0x58B51218, 0x4085E08D, 0xB68C484B
31 struct weblog_login *head;
32 struct weblog_login *tail;
33 } weblog_login_cache[WEBLOG_LOGIN_HASH_SIZE];
35 /* shchecksum.c copied here */
38 * This module implements the Secure Hash Algorithm (SHA) as specified in
39 * the Secure Hash Standard (SHS, FIPS PUB 180.1).
42 static int big_endian;
44 static const sha_int hashinit[] = {
45 0x67452301, 0xEFCDAB89, 0x98BADCFE,
46 0x10325476, 0xC3D2E1F0
49 #define ROTL(n, x) (((x) << (n)) | ((x) >> (SHA_BITS_PER_INT - (n))))
51 #ifdef DISABLED_CODE_HERE
53 f(int t, sha_int x, sha_int y, sha_int z)
55 if (t < 0 || t >= SHA_ROUNDS)
58 return (z ^ (x & (y ^ z)));
62 return ((x & y) | (z & (x | y))); /* saves 1 boolean op */
63 return (x ^ y ^ z); /* 60-79 same as 40-59 */
67 /* This is the "magic" function used for each round. */
68 /* Were this a C function, the interface would be: */
69 /* static sha_int f(int t, sha_int x, sha_int y, sha_int z) */
70 /* The function call version preserved above until stable */
72 #define f_a(x, y, z) (z ^ (x & (y ^ z)))
73 #define f_b(x, y, z) (x ^ y ^ z)
74 #define f_c(x, y, z) (( (x & y) | (z & (x | y))))
76 #define f(t, x, y, z) \
77 ( (t < 0 || t >= SHA_ROUNDS) ? 0 : \
78 ( (t < 20) ? f_a(x, y, z) : \
79 ( (t < 40) ? f_b(x, y, z) : \
80 ( (t < 60) ? f_c(x, y, z) : f_b(x, y, z)))))
83 *static sha_int K(int t)
85 * if (t < 0 || t >= SHA_ROUNDS) return 0;
96 /* This macro/function supplies the "magic" constant for each round. */
97 /* The function call version preserved above until stable */
99 static const sha_int k_vals[] =
100 { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
102 #define K(t) ( (t < 0 || t >= SHA_ROUNDS) ? 0 : k_vals[ t/20 ] )
105 * Update the internal state based on the given chunk.
108 transform(shaState * shaStateP, sha_int * chunk)
110 sha_int A = shaStateP->digest[0];
111 sha_int B = shaStateP->digest[1];
112 sha_int C = shaStateP->digest[2];
113 sha_int D = shaStateP->digest[3];
114 sha_int E = shaStateP->digest[4];
118 sha_int W[SHA_ROUNDS];
120 for (t = 0; t < SHA_CHUNK_INTS; t++)
122 for (; t < SHA_ROUNDS; t++) {
123 TEMP = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16];
124 W[t] = ROTL(1, TEMP);
127 for (t = 0; t < SHA_ROUNDS; t++) {
128 TEMP = ROTL(5, A) + f(t, B, C, D) + E + W[t] + K(t);
136 shaStateP->digest[0] += A;
137 shaStateP->digest[1] += B;
138 shaStateP->digest[2] += C;
139 shaStateP->digest[3] += D;
140 shaStateP->digest[4] += E;
145 * This function takes an array of SHA_CHUNK_BYTES bytes
146 * as input and produces an output array of ints that is
147 * SHA_CHUNK_INTS long.
150 buildInts(const char *data, sha_int * chunk)
153 * Need to copy the data because we can't be certain that
154 * the input buffer will be aligned correctly.
156 memcpy((void *)chunk, (void *)data, SHA_CHUNK_BYTES);
159 /* This loop does nothing but waste time on a big endian machine. */
162 for (i = 0; i < SHA_CHUNK_INTS; i++)
163 chunk[i] = ntohl(chunk[i]);
168 * This function updates the internal state of the hash by using
169 * buildInts to break the input up into chunks and repeatedly passing
170 * these chunks to transform().
173 sha_update(shaState * shaStateP, const char *buffer, int bufferLen)
176 sha_int chunk[SHA_CHUNK_INTS];
179 if (buffer == NULL || bufferLen == 0)
182 newLo = shaStateP->bitcountLo + (bufferLen << 3);
183 if (newLo < shaStateP->bitcountLo)
184 shaStateP->bitcountHi++;
185 shaStateP->bitcountLo = newLo;
186 shaStateP->bitcountHi += ((bufferLen >> (SHA_BITS_PER_INT - 3)) & 0x07);
189 * If we won't have enough for a full chunk, just tack this
190 * buffer onto the leftover piece and return.
192 if (shaStateP->leftoverLen + bufferLen < SHA_CHUNK_BYTES) {
193 memcpy((void *)&(shaStateP->leftover[shaStateP->leftoverLen]),
194 (void *)buffer, bufferLen);
195 shaStateP->leftoverLen += bufferLen;
199 /* If we have a leftover chunk, process it first. */
200 if (shaStateP->leftoverLen > 0) {
201 i = (SHA_CHUNK_BYTES - shaStateP->leftoverLen);
202 memcpy((void *)&(shaStateP->leftover[shaStateP->leftoverLen]),
206 buildInts(shaStateP->leftover, chunk);
207 shaStateP->leftoverLen = 0;
208 transform(shaStateP, chunk);
211 while (bufferLen >= SHA_CHUNK_BYTES) {
212 buildInts(buffer, chunk);
213 transform(shaStateP, chunk);
214 buffer += SHA_CHUNK_BYTES;
215 bufferLen -= SHA_CHUNK_BYTES;
217 /* assert((bufferLen >= 0) && (bufferLen < SHA_CHUNK_BYTES)); */
218 if ((bufferLen < 0) || (bufferLen > SHA_CHUNK_BYTES)) {
219 fprintf(stderr, "apache_afs_cache: ASSERTION FAILED...exiting\n");
224 memcpy((void *)&shaStateP->leftover[0], (void *)buffer, bufferLen);
225 shaStateP->leftoverLen = bufferLen;
231 * This method updates the internal state of the hash using
232 * any leftover data plus appropriate padding and incorporation
233 * of the hash bitcount to finish the hash. The hash value
234 * is not valid until finish() has been called.
237 sha_finish(shaState * shaStateP)
239 sha_int chunk[SHA_CHUNK_INTS];
242 if (shaStateP->leftoverLen > (SHA_CHUNK_BYTES - 9)) {
243 shaStateP->leftover[shaStateP->leftoverLen++] = 0x80;
244 memset(&(shaStateP->leftover[shaStateP->leftoverLen]), 0,
245 (SHA_CHUNK_BYTES - shaStateP->leftoverLen));
246 buildInts(shaStateP->leftover, chunk);
247 transform(shaStateP, chunk);
248 memset(chunk, 0, SHA_CHUNK_BYTES);
250 shaStateP->leftover[shaStateP->leftoverLen++] = 0x80;
251 memset(&(shaStateP->leftover[shaStateP->leftoverLen]), 0,
252 (SHA_CHUNK_BYTES - shaStateP->leftoverLen));
253 buildInts(shaStateP->leftover, chunk);
255 shaStateP->leftoverLen = 0;
257 chunk[SHA_CHUNK_INTS - 2] = shaStateP->bitcountHi;
258 chunk[SHA_CHUNK_INTS - 1] = shaStateP->bitcountLo;
259 transform(shaStateP, chunk);
264 * Initialize the hash to its "magic" initial value specified by the
265 * SHS standard, and clear out the bitcount and leftover vars.
266 * This should be used to initialize an shaState.
269 sha_clear(shaState * shaStateP)
271 big_endian = (0x01020304 == htonl(0x01020304));
273 memcpy((void *)&shaStateP->digest[0], (void *)&hashinit[0],
275 shaStateP->bitcountLo = shaStateP->bitcountHi = 0;
276 shaStateP->leftoverLen = 0;
281 * Hash the buffer and place the result in *shaStateP.
284 sha_hash(shaState * shaStateP, const char *buffer, int bufferLen)
286 sha_clear(shaStateP);
287 sha_update(shaStateP, buffer, bufferLen);
288 sha_finish(shaStateP);
293 * Returns the current state of the hash as an array of 20 bytes.
294 * This will be an interim result if finish() has not yet been called.
297 sha_bytes(const shaState * shaStateP, char *bytes)
299 sha_int temp[SHA_HASH_INTS];
302 for (i = 0; i < SHA_HASH_INTS; i++)
303 temp[i] = htonl(shaStateP->digest[i]);
304 memcpy(bytes, (void *)&temp[0], SHA_HASH_BYTES);
309 * Hash function for the AFS login cache
312 weblog_login_hash(char *name, char *cell)
316 for (val = *name, p = name; *p != '\0'; p++) {
317 val = (val << 2) ^ val ^ (afs_uint32) (*p);
319 for (p = cell; *p != '\0'; p++) {
320 val = (val << 2) ^ val ^ (afs_uint32) (*p);
322 return val & (WEBLOG_LOGIN_HASH_SIZE - 1);
326 * Compute a SHA checksum on the username, cellname, and password
329 weblog_login_checksum(char *user, char *cell, char *passwd, char *cksum)
338 * Compute SHA(username,SHA(password,pad))
340 passwdLen = strlen(passwd);
341 userLen = strlen(user);
342 cellLen = strlen(cell);
344 (char *)malloc(MAX(userLen + cellLen, passwdLen) + SHA_HASH_BYTES);
345 strcpy(shaBuffer, passwd);
346 memcpy((void *)(shaBuffer + passwdLen), (void *)(&weblog_login_pad[0]),
349 sha_hash(&state, shaBuffer, passwdLen + SHA_HASH_BYTES);
350 memcpy(shaBuffer, user, userLen);
351 memcpy(shaBuffer + userLen, cell, cellLen);
352 sha_bytes(&state, shaBuffer + userLen + cellLen);
354 sha_hash(&state, shaBuffer, userLen + cellLen + SHA_HASH_BYTES);
355 sha_bytes(&state, &cksum[0]);
356 memset(shaBuffer, 0, MAX(userLen + cellLen, passwdLen) + SHA_HASH_BYTES);
361 * Look up a login ID in the cache. If an entry name is found for the
362 * given username, and the SHA checksums match, then
363 * set the token parameter and return 1, otherwise return 0.
366 weblog_login_lookup(char *user, char *cell, char *cksum, char *token)
370 struct weblog_login *loginP, *tmpP, loginTmp;
373 * Search the hash chain for a matching entry, free
374 * expired entries as we search
376 index = weblog_login_hash(user, cell);
377 curTime = time(NULL);
379 loginP = weblog_login_cache[index].head;
380 while (loginP != NULL) {
381 if (loginP->expiration < curTime) {
385 DLL_DELETE(tmpP, weblog_login_cache[index].head,
386 weblog_login_cache[index].tail, next, prev);
390 if (strcmp(loginP->username, user) == 0
391 && strcmp(loginP->cellname, cell) == 0
392 && memcmp((void *)&loginP->cksum[0], (void *)cksum,
393 SHA_HASH_BYTES) == 0) {
395 memcpy((void *)token, (void *)&loginP->token[0], MAXBUFF);
396 return loginP->tokenLen;
398 loginP = loginP->next;
404 * Insert a login token into the cache. If the user already has an entry,
405 * then overwrite the old entry.
408 weblog_login_store(char *user, char *cell, char *cksum, char *token,
409 int tokenLen, afs_uint32 expiration)
413 struct weblog_login *loginP, *tmpP, loginTmp;
415 int parseToken(char *tokenBuf);
418 * Search the hash chain for a matching entry, free
419 * expired entries as we search
421 index = weblog_login_hash(user, cell);
422 curTime = time(NULL);
423 loginP = weblog_login_cache[index].head;
425 while (loginP != NULL) {
426 if (strcmp(loginP->username, user) == 0
427 && strcmp(loginP->cellname, cell) == 0) {
430 if (loginP->expiration < curTime) {
434 DLL_DELETE(tmpP, weblog_login_cache[index].head,
435 weblog_login_cache[index].tail, next, prev);
439 loginP = loginP->next;
441 if (loginP == NULL) {
442 loginP = (struct weblog_login *)malloc(sizeof(struct weblog_login));
443 strcpy(&loginP->username[0], user);
444 strcpy(&loginP->cellname[0], cell);
446 DLL_DELETE(loginP, weblog_login_cache[index].head,
447 weblog_login_cache[index].tail, next, prev);
450 memcpy((void *)&loginP->cksum[0], (void *)cksum, SHA_HASH_BYTES);
451 loginP->expiration = expiration;
452 loginP->tokenLen = getTokenLen(token);
453 memcpy((void *)&loginP->token[0], (void *)token, MAXBUFF);
455 DLL_INSERT_TAIL(loginP, weblog_login_cache[index].head,
456 weblog_login_cache[index].tail, next, prev);
463 for (i = 0; i < WEBLOG_LOGIN_HASH_SIZE; i++) {
464 DLL_INIT_LIST(weblog_login_cache[i].head, weblog_login_cache[i].tail);
469 getTokenLen(char *buf)
473 char cellName[WEBLOG_CELLNAME_MAX];
475 int n = sizeof(afs_int32);
477 afs_int32 AuthHandle;
478 char HandShakeKey[8];
480 afs_int32 BeginTimestamp;
481 afs_int32 EndTimestamp;
484 memcpy(&len, tp, sizeof(afs_int32)); /* get size of secret token */
485 rc = (len + sizeof(afs_int32));
486 tp += (sizeof(afs_int32) + len); /* skip secret token and its length */
487 memcpy(&len, tp, sizeof(afs_int32)); /* get size of clear token */
488 if (len != sizeof(struct ClearToken)) {
491 "apache_afs_cache.c:getExpiration:"
492 "something's wrong with the length of ClearToken:%d\n", len);
496 rc += (sizeof(afs_int32) + len); /* length of clear token + length itself */
497 tp += (sizeof(afs_int32) + len); /* skip clear token and its length */
498 rc += sizeof(afs_int32); /* length of primary flag */
499 tp += sizeof(afs_int32); /* skip over primary flag */
500 strcpy(cellName, tp);
501 if (cellName != NULL)
502 rc += strlen(cellName);
507 getExpiration(char *buf)
511 int n = sizeof(afs_int32);
513 afs_int32 AuthHandle;
514 char HandShakeKey[8];
516 afs_int32 BeginTimestamp;
517 afs_int32 EndTimestamp;
521 memcpy(&len, tp, sizeof(afs_int32)); /* get size of secret token */
522 tp += (sizeof(afs_int32) + len); /* skip secret token and its length */
523 memcpy(&len, tp, sizeof(afs_int32)); /* get size of clear token */
524 if (len != sizeof(struct ClearToken)) {
527 "apache_afs_cache.c:getExpiration:"
528 "something's wrong with the length of ClearToken:%d\n", len);
533 tp += sizeof(afs_int32); /* skip length of clear token */
534 memcpy(&token, tp, sizeof(struct ClearToken)); /* copy the token */
535 return token.EndTimestamp;