CVS: beepcore-c/threaded_os/profiles/SASLutils do_hash.c,NONE,1.1 global.h,NONE,1.1 md5.c,NONE,1.1 md5.h,NONE,1.1 otp_db.c,NONE,1.1 sasl_general.c,NONE,1.1 sasl_general.h,NONE,1.1

Chris Hanson <[email protected]> Sat, 07 Sep 2002 20:02:35 -0700
Newsgroups gmane.network.beep.beepcore.c.cvs
Message-ID <[email protected]>
Update of /cvsroot/beepcore-c/beepcore-c/threaded_os/profiles/SASLutils
In directory usw-pr-cvs1:/tmp/cvs-serv32474/threaded_os/profiles/SASLutils

Added Files:
	do_hash.c global.h md5.c md5.h otp_db.c sasl_general.c 
	sasl_general.h 
Log Message:
Move "profiles/" directory to "threaded_os/profiles/".


--- NEW FILE: do_hash.c ---
/*
 * Copyright (c) 2001 Invisible Worlds, Inc.  All rights reserved.
 *
 * The contents of this file are subject to the Blocks Public License (the
 * "License"); You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at http://www.beepcore.org/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 */

/*
 * This is the interface to the various hash routines.
 * It's separate, because we're using 3rd party code,
 * and all such code is baroque in different ways to
 * make it portable. This, however, exports just normal
 * C stuff.
 */

#include "global.h" /* For MD5 code */
#include "md5.h"
#include <stdlib.h>

void do_hash(int mechanism, char * source, int len, char dest[8]) {
    if (mechanism == 5) {
        MD5_CTX md5ctx;
        unsigned char md5out[16];
        int i;
        MD5Init(&md5ctx);
        MD5Update(&md5ctx, source, len);
        MD5Final(md5out, &md5ctx);
        for (i = 0; i < 8; i++)
            dest[i] = md5out[i] ^ md5out[i+8];
    } else {
        abort();
    }
}



--- NEW FILE: global.h ---


/* GLOBAL.H - RSAREF types and constants
 */
#ifndef SASLUTILS_GLOBAL_H
#define SASLUTILS_GLOBAL_H

/* PROTOTYPES should be set to one if and only if the compiler supports
  function argument prototyping.
The following makes PROTOTYPES default to 0 if it has not already
  been defined with C compiler flags.
 */
#ifndef PROTOTYPES
#define PROTOTYPES 1
#endif

/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;

/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;

/* UINT4 defines a four byte word */
typedef unsigned long int UINT4;

/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
  returns an empty list.
 */
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif

#endif /* SASLUTILS_GLOBAL_H */


--- NEW FILE: md5.c ---

/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
 */

/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.

License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.

License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.

RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.

These notices must be retained in any copies of any part of this
documentation and/or software.
 */

#include "global.h"
#include "md5.h"

/* Constants for MD5Transform routine.
 */

#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
static void Encode PROTO_LIST
  ((unsigned char *, UINT4 *, unsigned int));
static void Decode PROTO_LIST
  ((UINT4 *, unsigned char *, unsigned int));
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));

static unsigned char PADDING[64] = {
  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/* F, G, H and I are basic MD5 functions.
 */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits.
 */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
 */
#define FF(a, b, c, d, x, s, ac) { \
 (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
 (a) = ROTATE_LEFT ((a), (s)); \
 (a) += (b); \
  }
#define GG(a, b, c, d, x, s, ac) { \
 (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
 (a) = ROTATE_LEFT ((a), (s)); \
 (a) += (b); \
  }
#define HH(a, b, c, d, x, s, ac) { \
 (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
 (a) = ROTATE_LEFT ((a), (s)); \
 (a) += (b); \
  }
#define II(a, b, c, d, x, s, ac) { \
 (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
 (a) = ROTATE_LEFT ((a), (s)); \
 (a) += (b); \
  }

/* MD5 initialization. Begins an MD5 operation, writing a new context.
 */
void MD5Init (
MD5_CTX *context)                                        /* context */
{
  context->count[0] = context->count[1] = 0;
  /* Load magic initialization constants.
*/
  context->state[0] = 0x67452301;
  context->state[1] = 0xefcdab89;
  context->state[2] = 0x98badcfe;
  context->state[3] = 0x10325476;
}

/* MD5 block update operation. Continues an MD5 message-digest
  operation, processing another message block, and updating the
  context.
 */
void MD5Update (
MD5_CTX *context,                                        /* context */
unsigned char *input,                                /* input block */
unsigned int inputLen)                     /* length of input block */
{
  unsigned int i, index, partLen;

  /* Compute number of bytes mod 64 */
  index = (unsigned int)((context->count[0] >> 3) & 0x3F);

  /* Update number of bits */
  if ((context->count[0] += ((UINT4)inputLen << 3))
   < ((UINT4)inputLen << 3))
 context->count[1]++;
  context->count[1] += ((UINT4)inputLen >> 29);

  partLen = 64 - index;

  /* Transform as many times as possible.
*/
  if (inputLen >= partLen) {
 MD5_memcpy
   ((POINTER)&context->buffer[index], (POINTER)input, partLen);
 MD5Transform (context->state, context->buffer);

 for (i = partLen; i + 63 < inputLen; i += 64)
   MD5Transform (context->state, &input[i]);

 index = 0;
  }
  else
 i = 0;

  /* Buffer remaining input */
  MD5_memcpy
 ((POINTER)&context->buffer[index], (POINTER)&input[i],
  inputLen-i);
}

/* MD5 finalization. Ends an MD5 message-digest operation, writing the
  the message digest and zeroizing the context.
 */
void MD5Final (
unsigned char digest[16],                         /* message digest */
MD5_CTX *context)                                       /* context */
{
  unsigned char bits[8];
  unsigned int index, padLen;

  /* Save number of bits */
  Encode (bits, context->count, 8);

  /* Pad out to 56 mod 64.
*/
  index = (unsigned int)((context->count[0] >> 3) & 0x3f);
  padLen = (index < 56) ? (56 - index) : (120 - index);
  MD5Update (context, PADDING, padLen);

  /* Append length (before padding) */
  MD5Update (context, bits, 8);

  /* Store state in digest */
  Encode (digest, context->state, 16);

  /* Zeroize sensitive information.
*/
  MD5_memset ((POINTER)context, 0, sizeof (*context));
}

/* MD5 basic transformation. Transforms state based on block.
 */
static void MD5Transform (
UINT4 state[4],
unsigned char block[64])
{
  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];

  Decode (x, block, 64);

  /* Round 1 */
  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */

 /* Round 2 */
  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */

  /* Round 3 */
  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */

  /* Round 4 */
  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */

  state[0] += a;
  state[1] += b;
  state[2] += c;
  state[3] += d;

  /* Zeroize sensitive information.
 */
  MD5_memset ((POINTER)x, 0, sizeof (x));
}

/* Encodes input (UINT4) into output (unsigned char). Assumes len is
  a multiple of 4.
 */
static void Encode (
unsigned char *output,
UINT4 *input,
unsigned int len)
{
  unsigned int i, j;

  for (i = 0, j = 0; j < len; i++, j += 4) {
 output[j] = (unsigned char)(input[i] & 0xff);
 output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
 output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
 output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
  }
}

/* Decodes input (unsigned char) into output (UINT4). Assumes len is
  a multiple of 4.
 */
static void Decode (
UINT4 *output,
unsigned char *input,
unsigned int len)
{
  unsigned int i, j;

  for (i = 0, j = 0; j < len; i++, j += 4)
 output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
   (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}

/* Note: Replace "for loop" with standard memcpy if possible.
 */

static void MD5_memcpy (POINTER output,POINTER input,unsigned int len) {
  unsigned int i;

  for (i = 0; i < len; i++)
 output[i] = input[i];
}

/* Note: Replace "for loop" with standard memset if possible.
 */
static void MD5_memset (POINTER output,int value,unsigned int len) {
  unsigned int i;

  for (i = 0; i < len; i++)
 ((char *)output)[i] = (char)value;
}


--- NEW FILE: md5.h ---
/* MD5.H - header file for MD5C.C
 */

/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.

License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.

License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.

RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.

These notices must be retained in any copies of any part of this
documentation and/or software.
 */

#ifndef SASLUTILS_MD5_H
#define SASLUTILS_MD5_H

#include "global.h"

/* MD5 context. */
typedef struct {
  UINT4 state[4];                                   /* state (ABCD) */
  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
  unsigned char buffer[64];                         /* input buffer */
} MD5_CTX;

extern void MD5Init PROTO_LIST ((MD5_CTX *));
extern void MD5Update PROTO_LIST
  ((MD5_CTX *, unsigned char *, unsigned int));
extern void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));

#endif /* SASLUTILS_MD5_H */


--- NEW FILE: otp_db.c ---
/*
 * Copyright (c) 2001 Invisible Worlds, Inc.  All rights reserved.
 *
 * The contents of this file are subject to the Blocks Public License (the
 * "License"); You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at http://www.beepcore.org/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 */

/*
 * OTP DB interface routines.
 * These interface to wherever you're storing your passwords.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <windows.h>
#endif
#include "sasl_general.h"

/*
 * This locks a OTP password. The password to lock
 * belongs to the indicated authentication ID. The
 * return is 0 if all is well, 1 if no such user
 * is in the database, or 2 if the file was busy.
 *
 * The current implementation uses a separate file
 * and a separate .lock file for each user.
 *
 * A real implementation would break expired locks,
 * etc.
 */

#ifdef WIN32
int sasl_otp_lock(char *path,
        char * authID) {
    HANDLE handle;
    char fname[290];

    sprintf(fname, "%s/%s.LOCK", path, authID);
    handle = CreateFile(fname, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW,
        FILE_ATTRIBUTE_NORMAL, NULL);
    if (handle == INVALID_HANDLE_VALUE) {
	return 2;
    }
    CloseHandle(handle);

    handle = CreateFile(authID, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL, NULL);
    if (handle == INVALID_HANDLE_VALUE) {
        DeleteFile(fname);
        return -2;
    }
    CloseHandle(handle);
    return 0;
}
#else
int sasl_otp_lock(char *path,
        char * authID) {
    int handle;
    char fname[290];

    sprintf(fname, "%s/%s.LOCK", path, authID);
    handle = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0666);
    if (handle == -1) return 2;
    close(handle);
    handle = open(authID, O_RDWR);
    if (handle == -1) {
        unlink(fname);
        return -2;
    }
    close(handle);
    return 0;
}
#endif

/*
 * This unlocks a previously locked user name.
 * It does nothing if the name isn't locked.
 */

void sasl_otp_unlock(char *path,
        char * authID) {
    char fname[290];

    sprintf(fname, "%s/%s.LOCK", path, authID);
    unlink(fname);
}

/*
 * This reads an OTP record from the password database.
 * It returns 0 if all was well, else 1 for any problem.
 */

int sasl_otp_read(char *path,
        char * authID,
        char mech[8],
        int * count,
        char seed[64],
        char pass[8]) {
    FILE * pwfile;
    char count_str[20];
    char pass_encoded[18];
    char fname[290];

    sprintf(fname, "%s/%s", path, authID);
    pwfile = fopen(fname, "r");
    if (pwfile == NULL) return 1;
    if (NULL == fgets(mech, 8, pwfile)) {
        fclose(pwfile);
        return 1;
    }
    if (mech[strlen(mech)-1] == '\n')
        mech[strlen(mech)-1] = '\0';
    if (NULL == fgets(count_str, 20, pwfile)) {
        fclose(pwfile);
        return 1;
    }
    (*count) = atoi(count_str);
    if (NULL == fgets(seed, 64, pwfile)) {
        fclose(pwfile);
        return 1;
    }
    if (seed[strlen(seed)-1] == '\n')
        seed[strlen(seed)-1] = '\0';
    if (NULL == fgets(pass_encoded, 17, pwfile)) {
        fclose(pwfile);
        return 1;
    }
    from_hex(pass_encoded, 16, pass);
    fclose(pwfile);
    return 0;
}

/*
 * This writes an OTP record to the password database.
 * It returns 0 if all was well, else 1 for any problem.
 */

int sasl_otp_write(char *path,
        char * authID,
        char mech[8],
        int count,
        char seed[64],
        char pass[8]) {
    FILE * pwfile;
    char pass_encoded[18];
    char fname[290];

    sprintf(fname, "%s/%s", path, authID);
    pwfile = fopen(fname, "w");
    if (pwfile == NULL) return 1;
    to_hex(pass, pass_encoded);
    fprintf(pwfile, "%s\n%d\n%s\n%s\n", mech, count, seed, pass_encoded);
    fclose(pwfile);
    return 0;
}


--- NEW FILE: sasl_general.c ---
/*
 * Copyright (c) 2001 Invisible Worlds, Inc.  All rights reserved.
 *
 * The contents of this file are subject to the Blocks Public License (the
 * "License"); You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at http://www.beepcore.org/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 */

/*
 * This is generic routines used by all SASL profiles.
 * These are not the routines for DB management.
 */

#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>

/* No time to figure out cbeep-config wierdness */
#include <beepcore-c/base64.h>
#include "sasl_general.h"

/* Given a pointer to the payload of a frame or a piggyback string,
 * find the <blob>, parse out the base64 stuff, and decode the
 * base64. Store the data in parse_blob_data, and its length in
 * parse_blob_length. The input data should be \0 terminated.
 * Note this does a really sloppy job on error detection. Basically,
 * it looks for the string "blob", then a ">" after that, and 
 * parses all base-64 characters up to the next "<" sign.
 * It also does a trivial parse of the status='...' attribute
 * if it's there, and puts it in parse_blob_status.
 */

void parse_blob(char * data, struct sasl_data_block * sdb) {
    char * blobP;
    char b64[1000];
    int inx = 0;
    sdb->parse_blob_length = -1;
    sdb->parse_blob_status[0] = '\0';
    blobP = strstr(data, "blob");
    if (blobP == NULL) return; /* No blob */
    while (*blobP && *blobP != '>')
        blobP += 1;
    if (!*blobP) return; /* Bad syntax */
    sdb->parse_blob_length = 0;
    while (*blobP && *blobP != '<' && inx < sizeof(b64)-4) {
        if (   ('A' <= *blobP && *blobP <= 'Z') ||
               ('a' <= *blobP && *blobP <= 'z') ||
               ('0' <= *blobP && *blobP <= '9') ||
                '+' == *blobP ||
                '/' == *blobP ||
                '=' == *blobP ) {
           b64[inx++] = *blobP;
           b64[inx] = '\0';
        }
        blobP += 1;
    }
    if (inx != 0) {
        base64_decode_into(NULL, b64, sdb->parse_blob_data);
        sdb->parse_blob_length = base64_dsize(b64);
    }
    /* Now see if there's a status=... */
    blobP = strstr(data, "blob");
    while (*blobP && *blobP != '>' && 0 != strncmp(blobP, "status", 6))
        blobP += 1;
    if (*blobP == '\0' || *blobP == '>')
        return;
    while (*blobP && *blobP != '=')
        blobP += 1;
    while (*blobP && *blobP != '\'' && *blobP != '"')
        blobP += 1;
    if (*blobP) blobP += 1;
    inx = 0;
    while (*blobP && *blobP != '\'' && *blobP != '"' && 
            inx < sizeof(sdb->parse_blob_status) - 3) {
        sdb->parse_blob_status[inx++] = *blobP;
        blobP += 1;
        sdb->parse_blob_status[inx] = '\0';
    }
}

void to_hex(unsigned char hash[8], unsigned char hex[17]) {
    int inx;
    for (inx = 0; inx < 8; inx++) {
        sprintf(hex + 2 * inx, "%02x", hash[inx]);
    }
}

int from_hex(unsigned char * hex, int hex_len, unsigned char hash[8]) {
    int inx; int byte; int nybble; unsigned char c; unsigned hexval;
    inx = 0; byte = 0; nybble = 0;
    while (inx < hex_len && byte < 8) {
        while (inx < hex_len && isspace(hex[inx]))
            inx ++;
        if (hex_len <= inx) {
            return 0;
        }
        c = tolower(hex[inx]);
        if (!isxdigit(c)) {
            return 0;
        }
        if ('0' <= c && c <= '9') 
            hexval = c - '0';
        else
            hexval = c - 'a' + 10;
        if (nybble == 0)
            hash[byte] = hexval << 4;
        else
            hash[byte] += hexval;
        nybble += 1;
        if (nybble == 2) {
            byte += 1; nybble = 0;
        }
        inx += 1;
    }
    return 1;
}

/* 
 * This accepts the payload of an incoming frame, either a start payload or 
 * a frame. It checks to see if it's a valid anonymous login. If it
 * is, it returns a status complete and registers the name and mechanism.
 * If it isn't, it returns an appropriate error.
 */

int sasl_anonymous_server_guts (char *inframe,
                                struct sasl_data_block * sdb) {
    parse_blob (inframe, sdb);
    return SASL_COMPLETE;
}

/*
 * This takes trace information and formats a payload to login
 * anonymously.
 */

char *sasl_anonymous_client_guts (char *trace,
                                  struct sasl_data_block *sdb) {
    strcpy (sdb -> payload, "<blob>");
    if (trace)
        base64_encode_into (trace, strlen (trace),
                            sdb -> payload + strlen (sdb -> payload));
    strcat (sdb -> payload, "</blob>");

    return (sdb -> payload);
}


/*
 * This returns the payload of the first message from
 * client to server.
 */

char *sasl_otp_client_guts_1 (char *authenID,
                              char *authorID,
                              struct sasl_data_block *sdb) {
    unsigned char *up;
    unsigned char uncoded_payload[sizeof "<data> </data>" + (256 * 2)];

    if ((authenID == NULL)
            || strlen (authenID) > 255
            || ((authorID != NULL) && strlen (authorID) > 255))
        return NULL;

    up = uncoded_payload;
    if (authorID) {
        strcpy (uncoded_payload, authorID);
	up += strlen (up);
    }    
    *up++ = '\0';
    strcpy(up, authenID);
    up += strlen (up);

    strcpy (sdb -> payload, "<blob>");
    base64_encode_into (uncoded_payload, up - uncoded_payload,
                        sdb -> payload + strlen (sdb -> payload));
    strcat (sdb -> payload, "</blob>");

    return (sdb -> payload);
}


/*
 * This takes the payload with the <blob> that first arrives
 * from the client and returns what the client wants to know.
 */

int sasl_otp_server_guts_1(char * inframe, struct sasl_data_block * sdb) {
    int i, j;
    int locked;
    unsigned char seed[64];
    unsigned char mech[8];
    int count;
    unsigned char pass[8];
    unsigned char prompt[90];
    char prompt_encoded[180];

    parse_blob(inframe, sdb);
    if (sdb->parse_blob_length < 3)
        return SASL_ERROR_BLOB;
    for (i = j = 0; 
            i < sdb->parse_blob_length && i < 256 && 
            sdb->parse_blob_data[i]; j++, i++) 
        sdb->authorID[j] = sdb->parse_blob_data[i];
    sdb->authorID[j] = '\0';
    assert(strlen(sdb->authorID) < sizeof(sdb->authorID));
    if (i == sdb->parse_blob_length || i == 256)
        return SASL_ERROR_BLOB;
    i += 1;
    for (j = 0; 
            i < sdb->parse_blob_length && i < 256 && sdb->parse_blob_data[i]; 
            j++, i++) 
        sdb->authenID[j] = sdb->parse_blob_data[i];
    sdb->authenID[j] = '\0';
    assert(strlen(sdb->authenID) < sizeof(sdb->authenID));
    if (i != sdb->parse_blob_length)
        return SASL_ERROR_BLOB;
    if ((sdb->authorID[0]) && strcmp(sdb->authenID, sdb->authorID))
        return SASL_ERROR_PROXY;
    locked = sasl_otp_lock(sdb->path, sdb->authenID);
    if (locked == 1)
        return SASL_ERROR_USERNAME;
    else if (locked == 2)
        return SASL_ERROR_USERBUSY;
    i = sasl_otp_read(sdb->path, sdb->authenID, mech, &count, seed, pass);
    if (i != 0) {
        /* Couldn't read file, bad format, etc. */
        sasl_otp_unlock(sdb->path,sdb->authenID);
        return SASL_ERROR_USERNAME;
    }
    if (count <= 1) {
        sasl_otp_unlock(sdb->path,sdb->authenID);
        return SASL_ERROR_SEQUENCE;
    }
    sprintf(prompt, "otp-%s %d %s ext", mech, count-1, seed);
    base64_encode_into(prompt, strlen(prompt), prompt_encoded);
    sprintf(sdb->payload, "<blob>%s</blob>", prompt_encoded);
    return SASL_CONTINUE;
}

/*
 * This is the client side for answering the server's prompt.
 * Call it with the <blob> and the pass phrase from the user.
 */

char * sasl_otp_client_guts_2(char * inframe, char * user_pass, int *problem,
        struct sasl_data_block * sdb) {
    int mechanism;  /* 5 = md5, 1 = sha1 */
    int count;      /* how many times to hash */
    unsigned char seed[64];  /* Pointer to the seed string */
    int inx;        /* Pointer/counter */
    int seed_inx;   /* Pointer into seed aray */
    unsigned char to_hash[128];
    unsigned char hash[8];
    unsigned char to_encode[21];

    *problem = SASL_ERROR_BLOB;
    parse_blob(inframe, sdb);
    if (sdb->parse_blob_length < 8) return NULL;
    if (0 == strncmp(sdb->parse_blob_data, "otp-md5 ", 8))
        mechanism = 5;
#if 0
    else if (0 == strncmp(sdb->parse_blob_data, "otp-sha1 ", 9))
	mechanism = 1;
#endif
    else {
        *problem = SASL_ERROR_ALGORITHM;
        return NULL;
    }
    for (inx = 6; !isspace(sdb->parse_blob_data[inx]); inx++)
        if (sdb->parse_blob_length <= inx) return NULL;
    while (isspace(sdb->parse_blob_data[inx])) 
        if (sdb->parse_blob_length <= inx) return NULL;
        else inx += 1;
    count = 0;
    while ('0' <= sdb->parse_blob_data[inx] && 
            sdb->parse_blob_data[inx] <= '9') {
        count = count * 10 + sdb->parse_blob_data[inx] - '0';
        if (sdb->parse_blob_length <= ++inx) return NULL;
    }
    if (!isspace(sdb->parse_blob_data[inx])) return NULL;
    while (isspace(sdb->parse_blob_data[inx])) 
        if (sdb->parse_blob_length <= inx) return NULL;
        else inx += 1;
    seed_inx = 0;
    while (!isspace(sdb->parse_blob_data[inx]) && 
            inx < sdb->parse_blob_length &&
            seed_inx < sizeof(seed)-1) {
        seed[seed_inx++] = sdb->parse_blob_data[inx++];
        seed[seed_inx] = '\0';
    }
    /* OK, now the string is parsed. */
    strcpy(to_hash, seed);
    strcat(to_hash, user_pass);
    /* printf("c2: to_hash='%s', count=%d, mechanism=%d\n", to_hash, count, mechanism); */
    do_hash(mechanism, to_hash, strlen(to_hash), hash);
    for (inx = 0; inx < count; inx++) {
        memmove(to_hash, hash, 8);
        do_hash(mechanism, to_hash, 8, hash);
    }
    /* Now we're hashed. Put it back. */
    strcpy(to_encode, "hex:");
    to_hex(hash, &to_encode[strlen(to_encode)]);
    strcpy(sdb->payload, "<blob>");
    base64_encode_into(to_encode, strlen(to_encode), 
            sdb->payload + strlen(sdb->payload));
    strcat(sdb->payload, "</blob>");
    return sdb->payload;
}

/*
 * Call this when the client responds to the prompt.
 */

int sasl_otp_server_guts_2(char * inframe, struct sasl_data_block * sdb) {
    int inx;
    unsigned char client[8];  /* What the client sent */
    unsigned char client_hashed[8]; /* One hash of 'client' */
    int i;
    int mechanism = -1;  /* 5 = md5, 1 = sha1 */
    unsigned char mech[8];
    int count;      /* how many times to hash (once) */
    unsigned char seed[64];  /* Pointer to the seed string */
    unsigned char filed[8];  /* What's in the file */
    /* unsigned char debug[18]; *//* for debugging output */

    parse_blob(inframe, sdb);
    if (0 == strcmp(sdb->parse_blob_status, "abort"))
        return SASL_ABORTED;
    if (0 != strncmp(sdb->parse_blob_data, "hex:", 4))
        return SASL_ERROR_HEXONLY;
    from_hex(sdb->parse_blob_data + 4, sdb->parse_blob_length - 4, client);

    i = sasl_otp_read(sdb->path, sdb->authenID, mech, &count, seed, filed);
    if (i != 0) {
        /* Couldn't read file, bad format, etc. */
        sasl_otp_unlock(sdb->path,sdb->authenID);
        return SASL_ERROR_USERNAME;
    }
    if (count <= 1) {
        sasl_otp_unlock(sdb->path,sdb->authenID);
        return SASL_ERROR_SEQUENCE;
    }
    if (0 == strcmp(mech, "md5"))
        mechanism = 5;
    else if (0 == strcmp(mech, "sha1"))
        mechanism = 1;
    count -= 1;
    do_hash(mechanism, client, 8, client_hashed);
    /* Here, pass should match what the client sent me. */
    /* to_hex(client_hashed, debug); printf("calced    ch=%s\n", debug); */
    /* to_hex(filed, debug);         printf("calced filed=%s\n", debug); */
    for (inx = 0; inx < 8; inx++) {
        if (filed[inx] != client_hashed[inx]) {
            sasl_otp_unlock(sdb->path,sdb->authenID);
            return SASL_ERROR_BADHASH;
        }
    }
    sasl_otp_write(sdb->path, sdb->authenID, 
            (mechanism == 5) ? "md5" : "sha1", 
            count, seed, client);
    sasl_otp_unlock(sdb->path,sdb->authenID);
    return SASL_COMPLETE;
}

/*
 * This creates the initial database file entry.
 */
void sasl_otp_initial(char *path, char authenID[64], char mech[8], int count, char seed[64], char pass[64]) {
    int mechanism;  /* 5 = md5, 1 = sha1 */
    int i;
    unsigned char hash[8];
    unsigned char temp[8];
    char phrase[130];

    if (0 != strcmp(mech, "md5")) {
        printf("Only md5 implemented now.\n");
        exit(1);
    } else {
        mechanism = 5;
    }
    strcpy(phrase, seed);
    strcat(phrase,pass);
    do_hash(mechanism, phrase, strlen(phrase), hash);
    /* to_hex(hash, phrase); printf("first hash=%s\n", phrase); */
    for (i = 0; i < count; i++) {
        memmove(temp, hash, 8);
        do_hash(mechanism, temp, 8, hash);
        /* to_hex(hash, phrase); printf("hash %d=%s\n", i, phrase); */
    }
    sasl_otp_write(path, authenID, 
            (mechanism == 5) ? "md5" : "sha1", 
            count, seed, hash);
    for (; i < count + 3; i++) {
        memmove(temp, hash, 8);
        do_hash(mechanism, temp, 8, hash);
        /* to_hex(hash, phrase); printf("hash %d=%s\n", i, phrase); */
    }
}



#if 0
static void test() {
    char * x;
    char * y;
    struct sasl_data_block sdb;
    struct sasl_data_block sdbC;
    struct sasl_data_block sdbS;

x = "content-type:application/beep+xml\r\n\r\n<start pro='...'><blob status='Yeppers!'>SGVsbG8=</blob>";

    parse_blob(x, &sdb);
    printf("parse_blob_data='%s'\n", sdb.parse_blob_data);
    printf("parse_blob_length='%d'\n", sdb.parse_blob_length);
    printf("parse_blob_status='%s'\n", sdb.parse_blob_status);

x = "content-type:application/beep+xml\r\n\r\n<start pro='...'><blob>SGVsbG8=</blob> status=\"whoops\"";
    parse_blob(x, &sdb);
    printf("parse_blob_data='%s'\n", sdb.parse_blob_data);
    printf("parse_blob_length='%d'\n", sdb.parse_blob_length);
    printf("parse_blob_status='%s'\n", sdb.parse_blob_status);

    x = "<blob>ZG5ld0BpbnZpc2libGUubmV0</blob>"; /* "[email protected]" */
    y = sasl_anonymous_server_guts(x, &sdb);
    printf("%s? %s!\n", sdb.parse_blob_data, y);

    x = "<blob>ZG5ldw==</blob>"; /* dnew */
    y = sasl_anonymous_server_guts(x, &sdb);
    printf("%s? %s!\n", sdb.parse_blob_data, y);

    x = "<blob>QGludmlzaWJsZS5uZXQ=</blob>"; /* @invisible.net */
    y = sasl_anonymous_server_guts(x, &sdb);
    printf("%s? %s!\n", sdb.parse_blob_data, y);

    x = "<blob>eEBpbnZpc2libGUubmV0</blob>"; /* [email protected] */
    y = sasl_anonymous_server_guts(x, &sdb);
    printf("%s? %s!\n", sdb.parse_blob_data, y);

    x = sasl_anonymous_client_guts_1("[email protected]", &sdbC);
    y = sasl_anonymous_server_guts(x, &sdbS);
    printf("%s? %s!\n", sdbS.parse_blob_data, y);

    printf("\n\n----------------\n\n");
    sasl_otp_initial("dnew@iw", "md5", 3, "seed42", "hello world");
    /* system("more /tmp/dnew@iw"); system("sleep 15"); */

    x = sasl_otp_client_guts_1("dnew@iw", &sdbC);
    parse_blob(x, &sdb);
    printf("client_1 = %s = %s\n", x, sdb.parse_blob_data);
    y = sasl_otp_server_guts_1(x, &sdbS);
    parse_blob(y, &sdb);
    printf("server_1 = %s = %s\n", y?y:"*NULL*", sdb.parse_blob_data);

    x = sasl_otp_client_guts_2(y, "hello world", &sdbC);
    if (x == NULL) {
      printf("client_2 returned null, %s\n", sdbC.parse_blob_data);
    } else {
      parse_blob(x, &sdb);
      printf("client_2 = %s = %s\n", x, sdb.parse_blob_data);
    }
    y = sasl_otp_server_guts_2(x, &sdbS);
    parse_blob(y, &sdb);
    printf("server_2 = %s = %s\n", y, sdb.parse_blob_data);


    { char abc[1000]; char pdq[1000];
      int i; int j;
      for (i = 1; i < 10; i++) {
        base64_encode_into("[email protected]", i, abc);
        j = base64_decode_into(NULL, abc, pdq); 
        if (j != i || 0 != strncmp("[email protected]", pdq, i))
          printf("%d %d %s %s\n", i, j, abc, pdq);
      }
    }

    /* OK.  A real base64 test. */
    { unsigned char abc[4]; unsigned char pdq[8]; unsigned char xyz[4];
      int i, j;
      for (i = 0; i < 256; i++) {
        abc[0] = i;
        base64_encode_into(abc, 1, pdq);
        j = base64_decode_into(NULL, pdq, xyz);
        if (j != 1 || xyz[0] != abc[0]) {
          printf("Fault 1: i=%d, j=%d, xyz[0] = %d, abc[0] = %d\n",
            i, j, xyz[0], abc[0]);
        }
      }
      for (i = 0; i < 65536; i++) {
        abc[0] = i % 256;
        abc[1] = i / 256;
        base64_encode_into(abc, 2, pdq);
        j = base64_decode_into(NULL, pdq, xyz);
        if (j != 2 || xyz[0] != abc[0] || xyz[1] != abc[1]) {
          printf("Fault 2: i=%d, j=%d, xyz[0] = %d, abc[0] = %d\n\txyz[1]=%d, abc[1]=%d\n",
            i, j, xyz[0], abc[0], xyz[1], abc[1]);
        }
      }
    }

    /* Now a to_hex from_hex test */
    { unsigned char hash[8]; unsigned char hex[17]; unsigned char unhash[8];
        int inx;
        for (inx = 0; inx < 8; inx++) {
            hash[inx] = ((inx + 5) << 4) + inx;
            /* printf("filling hash[%d]=%x\n", inx, hash[inx]); */
        }
        to_hex(hash, hex);
        if (0 != strcmp(hex, "5061728394a5b6c7")) {
            printf("to_hex returned %s\n", hex);
        }
        inx = from_hex(hex, strlen(hex), unhash);
        if (!inx) 
          printf("from_hex returned zero\n");
        for (inx = 0; inx < 8; inx++) {
            if (hash[inx] != unhash[inx]) {
                printf("hash[%d]=%x, unhash[%d]=%x\n", 
                        inx, hash[inx], inx, unhash[inx]);
            }
        }
    }

}

int main() {
    test();
    return 0;
}
#endif


--- NEW FILE: sasl_general.h ---
/*
 * Copyright (c) 2001 Invisible Worlds, Inc.  All rights reserved.
 *
 * The contents of this file are subject to the Blocks Public License (the
 * "License"); You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at http://www.beepcore.org/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 */

/*
 * This is generic routines used by all SASL profiles.
 * These are not the routines for DB management.
 */

struct sasl_data_block {
    char *path;
    unsigned char parse_blob_data[1000];
    int parse_blob_length; /* gets <0 for problems */
    char parse_blob_status[25];
    char payload[800];  /* Return value */
    char authenID[260];
    char authorID[260];
    int locked;
};

#define SASL_ALREADY_DONE     (-3)
#define SASL_ABORTED          (-2)
#define SASL_CONTINUE         (-1)
#define SASL_COMPLETE           0
#define SASL_ERROR_BLOB         1
#define SASL_ERROR_TRACE        2
#define SASL_ERROR_PROXY        3
#define SASL_ERROR_USERNAME     4
#define SASL_ERROR_USERBUSY     5
#define SASL_ERROR_SEQUENCE     6
#define SASL_ERROR_HEXONLY      7
#define SASL_ERROR_BADHASH      8
#define SASL_ERROR_ALGORITHM    9

int sasl_anonymous_server_guts (char *inframe, struct sasl_data_block *sdb);
int sasl_otp_server_guts_1     (char *inframe, struct sasl_data_block *sdb);
int sasl_otp_server_guts_2     (char *inframe, struct sasl_data_block *sdb);


char *sasl_anonymous_client_guts (char *trace, struct sasl_data_block *sdb);
char *sasl_otp_client_guts_1     (char *authenID, char *authorID,
                                               struct sasl_data_block *sdb);
char *sasl_otp_client_guts_2     (char *nframe, char *user_pass, int *problem,
                                               struct sasl_data_block *sdb);


void parse_blob(char * data, struct sasl_data_block * sdb);

void to_hex(unsigned char hash[8], unsigned char hex[17]);

int from_hex(unsigned char * hex, int hex_len, unsigned char hash[8]);

void sasl_otp_initial(char *path, char authenID[64], char mech[8], int count, char seed[64], char pass[64]);

int sasl_otp_lock(char *path,
        char * authID);

void sasl_otp_unlock(char *path,
        char * authID);

int sasl_otp_read(char *path,
        char * authID,
        char mech[8],
        int * count,
        char seed[64],
        char pass[8]);

int sasl_otp_write(char *path,
        char * authID,
        char mech[8],
        int count,
        char seed[64],
        char pass[8]);

void do_hash(int mechanism, char * source, int len, char dest[8]);



-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old
cell phone?  Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390