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 <afs/param.h>
13 #include <afsconfig.h>
17 #include "apache_afs_cache.h"
20 * Value used to initialize SHA checksums on username/password pairs
22 afs_uint32 weblog_login_pad[SHA_HASH_INTS] = {
23 0x0D544971, 0x2281AC5B, 0x58B51218, 0x4085E08D, 0xB68C484B
30 struct weblog_login *head;
31 struct weblog_login *tail;
32 } weblog_login_cache[WEBLOG_LOGIN_HASH_SIZE];
34 /* shchecksum.c copied here */
37 * This module implements the Secure Hash Algorithm (SHA) as specified in
38 * the Secure Hash Standard (SHS, FIPS PUB 180.1).
41 static int big_endian;
43 static const sha_int hashinit[] = {
44 0x67452301, 0xEFCDAB89, 0x98BADCFE,
45 0x10325476, 0xC3D2E1F0
48 #define ROTL(n, x) (((x) << (n)) | ((x) >> (SHA_BITS_PER_INT - (n))))
50 #ifdef DISABLED_CODE_HERE
51 static sha_int f(int t, sha_int x, sha_int y, sha_int z)
53 if (t < 0 || t >= SHA_ROUNDS) return 0;
55 return (z ^ (x & (y ^ z)));
59 return ((x & y) | (z & (x | y))); /* saves 1 boolean op */
60 return (x ^ y ^ z); /* 60-79 same as 40-59 */
64 /* This is the "magic" function used for each round. */
65 /* Were this a C function, the interface would be: */
66 /* static sha_int f(int t, sha_int x, sha_int y, sha_int z) */
67 /* The function call version preserved above until stable */
69 #define f_a(x, y, z) (z ^ (x & (y ^ z)))
70 #define f_b(x, y, z) (x ^ y ^ z)
71 #define f_c(x, y, z) (( (x & y) | (z & (x | y))))
73 #define f(t, x, y, z) \
74 ( (t < 0 || t >= SHA_ROUNDS) ? 0 : \
75 ( (t < 20) ? f_a(x, y, z) : \
76 ( (t < 40) ? f_b(x, y, z) : \
77 ( (t < 60) ? f_c(x, y, z) : f_b(x, y, z)))))
80 *static sha_int K(int t)
82 * if (t < 0 || t >= SHA_ROUNDS) return 0;
93 /* This macro/function supplies the "magic" constant for each round. */
94 /* The function call version preserved above until stable */
96 static const sha_int k_vals[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6};
98 #define K(t) ( (t < 0 || t >= SHA_ROUNDS) ? 0 : k_vals[ t/20 ] )
101 * Update the internal state based on the given chunk.
103 static void transform(shaState *shaStateP, sha_int *chunk)
105 sha_int A = shaStateP->digest[0];
106 sha_int B = shaStateP->digest[1];
107 sha_int C = shaStateP->digest[2];
108 sha_int D = shaStateP->digest[3];
109 sha_int E = shaStateP->digest[4];
113 sha_int W[SHA_ROUNDS];
115 for (t = 0; t < SHA_CHUNK_INTS; t++)
117 for (; t < SHA_ROUNDS; t++) {
118 TEMP = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
119 W[t] = ROTL(1, TEMP);
122 for (t = 0; t < SHA_ROUNDS; t++) {
123 TEMP = ROTL(5, A) + f(t, B, C, D) + E + W[t] + K(t);
124 E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
127 shaStateP->digest[0] += A;
128 shaStateP->digest[1] += B;
129 shaStateP->digest[2] += C;
130 shaStateP->digest[3] += D;
131 shaStateP->digest[4] += E;
136 * This function takes an array of SHA_CHUNK_BYTES bytes
137 * as input and produces an output array of ints that is
138 * SHA_CHUNK_INTS long.
140 static void buildInts(const char *data, sha_int *chunk)
143 * Need to copy the data because we can't be certain that
144 * the input buffer will be aligned correctly.
146 memcpy((void *)chunk, (void *)data, SHA_CHUNK_BYTES);
149 /* This loop does nothing but waste time on a big endian machine. */
152 for (i = 0; i < SHA_CHUNK_INTS; i++)
153 chunk[i] = ntohl(chunk[i]);
158 * This function updates the internal state of the hash by using
159 * buildInts to break the input up into chunks and repeatedly passing
160 * these chunks to transform().
162 void sha_update(shaState *shaStateP, const char *buffer, int bufferLen)
165 sha_int chunk[SHA_CHUNK_INTS];
168 if (buffer == NULL || bufferLen == 0)
171 newLo = shaStateP->bitcountLo + (bufferLen << 3);
172 if (newLo < shaStateP->bitcountLo)
173 shaStateP->bitcountHi++;
174 shaStateP->bitcountLo = newLo;
175 shaStateP->bitcountHi += ((bufferLen >> (SHA_BITS_PER_INT - 3)) & 0x07);
178 * If we won't have enough for a full chunk, just tack this
179 * buffer onto the leftover piece and return.
181 if (shaStateP->leftoverLen + bufferLen < SHA_CHUNK_BYTES) {
182 memcpy((void *)&(shaStateP->leftover[shaStateP->leftoverLen]),
183 (void *)buffer, bufferLen);
184 shaStateP->leftoverLen += bufferLen;
188 /* If we have a leftover chunk, process it first. */
189 if (shaStateP->leftoverLen > 0) {
190 i = (SHA_CHUNK_BYTES - shaStateP->leftoverLen);
191 memcpy((void *)&(shaStateP->leftover[shaStateP->leftoverLen]),
195 buildInts(shaStateP->leftover, chunk);
196 shaStateP->leftoverLen = 0;
197 transform(shaStateP, chunk);
200 while (bufferLen >= SHA_CHUNK_BYTES) {
201 buildInts(buffer, chunk);
202 transform(shaStateP, chunk);
203 buffer += SHA_CHUNK_BYTES;
204 bufferLen -= SHA_CHUNK_BYTES;
206 /* assert((bufferLen >= 0) && (bufferLen < SHA_CHUNK_BYTES)); */
207 if ((bufferLen < 0) || (bufferLen > SHA_CHUNK_BYTES) ) {
208 fprintf(stderr, "apache_afs_cache: ASSERTION FAILED...exiting\n");
213 memcpy((void *)&shaStateP->leftover[0], (void *)buffer, bufferLen);
214 shaStateP->leftoverLen = bufferLen;
220 * This method updates the internal state of the hash using
221 * any leftover data plus appropriate padding and incorporation
222 * of the hash bitcount to finish the hash. The hash value
223 * is not valid until finish() has been called.
225 void sha_finish(shaState *shaStateP)
227 sha_int chunk[SHA_CHUNK_INTS];
230 if (shaStateP->leftoverLen > (SHA_CHUNK_BYTES - 9)) {
231 shaStateP->leftover[shaStateP->leftoverLen++] = 0x80;
232 memset(&(shaStateP->leftover[shaStateP->leftoverLen]), 0,
233 (SHA_CHUNK_BYTES - shaStateP->leftoverLen));
234 buildInts(shaStateP->leftover, chunk);
235 transform(shaStateP, chunk);
236 memset(chunk, 0, SHA_CHUNK_BYTES);
238 shaStateP->leftover[shaStateP->leftoverLen++] = 0x80;
239 memset(&(shaStateP->leftover[shaStateP->leftoverLen]), 0,
240 (SHA_CHUNK_BYTES - shaStateP->leftoverLen));
241 buildInts(shaStateP->leftover, chunk);
243 shaStateP->leftoverLen = 0;
245 chunk[SHA_CHUNK_INTS - 2] = shaStateP->bitcountHi;
246 chunk[SHA_CHUNK_INTS - 1] = shaStateP->bitcountLo;
247 transform(shaStateP, chunk);
252 * Initialize the hash to its "magic" initial value specified by the
253 * SHS standard, and clear out the bitcount and leftover vars.
254 * This should be used to initialize an shaState.
256 void sha_clear(shaState *shaStateP)
258 big_endian = (0x01020304 == htonl(0x01020304));
260 memcpy((void *)&shaStateP->digest[0], (void *)&hashinit[0], SHA_HASH_BYTES);
261 shaStateP->bitcountLo = shaStateP->bitcountHi = 0;
262 shaStateP->leftoverLen = 0;
267 * Hash the buffer and place the result in *shaStateP.
269 void sha_hash(shaState *shaStateP, const char *buffer, int bufferLen)
271 sha_clear(shaStateP);
272 sha_update(shaStateP, buffer, bufferLen);
273 sha_finish(shaStateP);
278 * Returns the current state of the hash as an array of 20 bytes.
279 * This will be an interim result if finish() has not yet been called.
281 void sha_bytes(const shaState *shaStateP, char *bytes)
283 sha_int temp[SHA_HASH_INTS];
286 for (i = 0; i < SHA_HASH_INTS; i++)
287 temp[i] = htonl(shaStateP->digest[i]);
288 memcpy(bytes, (void *)&temp[0], SHA_HASH_BYTES);
293 * Hash function for the AFS login cache
295 int weblog_login_hash(char *name, char *cell)
299 for (val = *name , p = name ; *p != '\0' ; p++) {
300 val = (val << 2) ^ val ^ (afs_uint32)(*p);
302 for (p = cell ; *p != '\0' ; p++) {
303 val = (val << 2) ^ val ^ (afs_uint32)(*p);
305 return val & (WEBLOG_LOGIN_HASH_SIZE-1);
309 * Compute a SHA checksum on the username, cellname, and password
311 void weblog_login_checksum(
324 * Compute SHA(username,SHA(password,pad))
326 passwdLen = strlen(passwd);
327 userLen = strlen(user);
328 cellLen = strlen(cell);
329 shaBuffer = (char *) malloc(MAX(userLen+cellLen,passwdLen)+SHA_HASH_BYTES);
330 strcpy(shaBuffer, passwd);
331 memcpy((void *)(shaBuffer + passwdLen), (void *)(&weblog_login_pad[0]),
334 sha_hash(&state, shaBuffer, passwdLen+SHA_HASH_BYTES);
335 memcpy(shaBuffer, user, userLen);
336 memcpy(shaBuffer+userLen, cell, cellLen);
337 sha_bytes(&state, shaBuffer+userLen+cellLen);
339 sha_hash(&state, shaBuffer, userLen+cellLen+SHA_HASH_BYTES);
340 sha_bytes(&state, &cksum[0]);
341 memset(shaBuffer, 0, MAX(userLen+cellLen,passwdLen)+SHA_HASH_BYTES);
346 * Look up a login ID in the cache. If an entry name is found for the
347 * given username, and the SHA checksums match, then
348 * set the token parameter and return 1, otherwise return 0.
350 int weblog_login_lookup(
358 struct weblog_login *loginP, *tmpP, loginTmp;
361 * Search the hash chain for a matching entry, free
362 * expired entries as we search
364 index = weblog_login_hash(user, cell);
365 curTime = time(NULL);
367 loginP = weblog_login_cache[index].head;
368 while (loginP != NULL) {
369 if (loginP->expiration < curTime) {
373 DLL_DELETE(tmpP, weblog_login_cache[index].head,
374 weblog_login_cache[index].tail, next, prev);
378 if (strcmp(loginP->username, user) == 0 &&
379 strcmp(loginP->cellname, cell) == 0 &&
380 memcmp((void *)&loginP->cksum[0], (void *)cksum,SHA_HASH_BYTES) == 0) {
382 memcpy((void *)token, (void *) &loginP->token[0], MAXBUFF);
383 return loginP->tokenLen;
385 loginP = loginP->next;
391 * Insert a login token into the cache. If the user already has an entry,
392 * then overwrite the old entry.
394 int weblog_login_store(
400 afs_uint32 expiration)
404 struct weblog_login *loginP, *tmpP, loginTmp;
406 int parseToken(char *tokenBuf);
409 * Search the hash chain for a matching entry, free
410 * expired entries as we search
412 index = weblog_login_hash(user, cell);
413 curTime = time(NULL);
414 loginP = weblog_login_cache[index].head;
416 while (loginP != NULL) {
417 if (strcmp(loginP->username, user) == 0 &&
418 strcmp(loginP->cellname, cell) == 0) {
421 if (loginP->expiration < curTime) {
425 DLL_DELETE(tmpP, weblog_login_cache[index].head,
426 weblog_login_cache[index].tail, next, prev);
430 loginP = loginP->next;
432 if (loginP == NULL) {
433 loginP = (struct weblog_login *)malloc(sizeof(struct weblog_login));
434 strcpy(&loginP->username[0], user);
435 strcpy(&loginP->cellname[0], cell);
438 DLL_DELETE(loginP, weblog_login_cache[index].head,
439 weblog_login_cache[index].tail, next, prev);
442 memcpy((void *)&loginP->cksum[0], (void *)cksum, SHA_HASH_BYTES);
443 loginP->expiration = expiration;
444 loginP->tokenLen=getTokenLen(token);
445 memcpy((void *)&loginP->token[0], (void *)token, MAXBUFF);
447 DLL_INSERT_TAIL(loginP, weblog_login_cache[index].head,
448 weblog_login_cache[index].tail, next, prev);
455 for (i = 0 ; i < WEBLOG_LOGIN_HASH_SIZE ; i++) {
456 DLL_INIT_LIST(weblog_login_cache[i].head,
457 weblog_login_cache[i].tail);
461 int getTokenLen(char *buf)
465 char cellName[WEBLOG_CELLNAME_MAX];
467 int n = sizeof(afs_int32);
469 afs_int32 AuthHandle;
470 char HandShakeKey[8];
472 afs_int32 BeginTimestamp;
473 afs_int32 EndTimestamp;
476 bcopy(tp, &len, sizeof(afs_int32)); /* get size of secret token */
477 rc=(len+sizeof(afs_int32));
478 tp += (sizeof(afs_int32) + len); /* skip secret token and its length */
479 bcopy(tp, &len, sizeof(afs_int32)); /* get size of clear token */
480 if (len != sizeof(struct ClearToken)) {
482 fprintf(stderr, "apache_afs_cache.c:getExpiration:"
483 "something's wrong with the length of ClearToken:%d\n", len);
487 rc+=(sizeof(afs_int32)+len); /* length of clear token + length itself */
488 tp+=(sizeof(afs_int32)+len); /* skip clear token and its length */
489 rc+=sizeof(afs_int32); /* length of primary flag */
490 tp+=sizeof(afs_int32); /* skip over primary flag */
491 strcpy(cellName, tp);
492 if (cellName != NULL)
493 rc+=strlen(cellName);
497 long getExpiration(char *buf)
501 int n = sizeof(afs_int32);
503 afs_int32 AuthHandle;
504 char HandShakeKey[8];
506 afs_int32 BeginTimestamp;
507 afs_int32 EndTimestamp;
511 bcopy(tp, &len, sizeof(afs_int32)); /* get size of secret token */
512 tp += (sizeof(afs_int32) + len); /* skip secret token and its length */
513 bcopy(tp, &len, sizeof(afs_int32)); /* get size of clear token */
514 if (len != sizeof(struct ClearToken)) {
516 fprintf(stderr, "apache_afs_cache.c:getExpiration:"
517 "something's wrong with the length of ClearToken:%d\n", len);
522 tp += sizeof(afs_int32); /* skip length of clear token */
523 bcopy(tp, &token, sizeof(struct ClearToken)); /* copy the token */
524 return token.EndTimestamp;