From 03846211ba84582b133a985200502a39462dfe66 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Wed, 9 Apr 1997 07:55:49 +0000 Subject: [PATCH] Initial revision --- lib/alloc.c | 19 ++ lib/alloc_str.c | 19 ++ lib/config.h | 37 ++++ lib/ctmatch.c | 43 +++++ lib/lib.h | 109 +++++++++++ lib/lists.c | 74 ++++++++ lib/lists.h | 98 ++++++++++ lib/log.c | 77 ++++++++ lib/log.h | 14 ++ lib/log2.c | 26 +++ lib/md5.c | 247 +++++++++++++++++++++++++ lib/md5.h | 22 +++ lib/patmatch.c | 37 ++++ lib/str_ctype.c | 13 ++ lib/str_upper.c | 13 ++ lib/temp.c | 49 +++++ lib/url.c | 479 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/url.h | 63 +++++++ lib/wordsplit.c | 30 +++ 19 files changed, 1469 insertions(+) create mode 100644 lib/alloc.c create mode 100644 lib/alloc_str.c create mode 100644 lib/config.h create mode 100644 lib/ctmatch.c create mode 100644 lib/lib.h create mode 100644 lib/lists.c create mode 100644 lib/lists.h create mode 100644 lib/log.c create mode 100644 lib/log.h create mode 100644 lib/log2.c create mode 100644 lib/md5.c create mode 100644 lib/md5.h create mode 100644 lib/patmatch.c create mode 100644 lib/str_ctype.c create mode 100644 lib/str_upper.c create mode 100644 lib/temp.c create mode 100644 lib/url.c create mode 100644 lib/url.h create mode 100644 lib/wordsplit.c diff --git a/lib/alloc.c b/lib/alloc.c new file mode 100644 index 00000000..65594669 --- /dev/null +++ b/lib/alloc.c @@ -0,0 +1,19 @@ +/* + * Sherlock Library -- Memory Allocation + * + * (c) 1997 Martin Mares, + */ + +#include +#include + +#include "lib.h" + +void * +xmalloc(uns size) +{ + void *x = malloc(size); + if (!x) + die("Cannot allocate %d bytes of memory", size); + return x; +} diff --git a/lib/alloc_str.c b/lib/alloc_str.c new file mode 100644 index 00000000..7c9f92de --- /dev/null +++ b/lib/alloc_str.c @@ -0,0 +1,19 @@ +/* + * Sherlock Library -- String Allocation + * + * (c) 1997 Martin Mares, + */ + +#include +#include + +#include "lib.h" + +byte * +stralloc(byte *s) +{ + uns l = strlen(s); + byte *k = xmalloc(l + 1); + strcpy(k, s); + return k; +} diff --git a/lib/config.h b/lib/config.h new file mode 100644 index 00000000..8b09c820 --- /dev/null +++ b/lib/config.h @@ -0,0 +1,37 @@ +/* + * Sherlock Library -- Configuration-Dependent Definitions + * + * (c) 1997 Martin Mares, + */ + +/* Version */ + +#define SHER_VER "0.1" + +/* Types */ + +typedef unsigned char byte; /* exactly 8 bits, unsigned */ +typedef signed char sbyte; /* exactly 8 bits, signed */ +typedef unsigned short word; /* exactly 16 bits, unsigned */ +typedef short sword; /* exactly 16 bits, signed */ +typedef unsigned int ulg; /* exactly 32 bits, unsigned */ +typedef int slg; /* exactly 32 bits, signed */ +typedef unsigned int uns; /* at least 32 bits */ + +/* Misc */ + +#ifdef __GNUC__ + +#undef inline +#define NONRET __attribute__((noreturn)) + +#else + +#define inline +#define NONRET + +#endif + +#ifdef linux +#define HAVE_FFS +#endif diff --git a/lib/ctmatch.c b/lib/ctmatch.c new file mode 100644 index 00000000..7a7d9674 --- /dev/null +++ b/lib/ctmatch.c @@ -0,0 +1,43 @@ +/* + * Sherlock Library -- Content-Type Pattern Matching + * + * (c) 1997 Martin Mares, + */ + +#include + +#include "lib.h" +#include "string.h" + +int +match_ct_patt(byte *p, byte *t) +{ + if (*p == '*' && !p[1]) /* "*" matches everything */ + return 1; + + if (*p == '*' && p[1] == '/') /* "*" on the left-hand side */ + { + while (*t && *t != ' ' && *t != ';' && *t != '/') + t++; + p += 2; + } + else /* Normal left-hand side */ + { + while (*p != '/') + if (Cupcase(*p++) != Cupcase(*t++)) + return 0; + p++; + } + if (*t != '/') + return 0; + + if (*p == '*' && p[1] == '/') /* "*" on the right-hand side */ + return 1; + while (*p) + if (Cupcase(*p++) != Cupcase(*t++)) + return 0; + if (*t && *t != ' ' && *t != ';') + return 0; + + return 1; +} diff --git a/lib/lib.h b/lib/lib.h new file mode 100644 index 00000000..e58e52a4 --- /dev/null +++ b/lib/lib.h @@ -0,0 +1,109 @@ +/* + * Sherlock Library -- Miscellaneous Functions + * + * (c) 1997 Martin Mares, + */ + +#include + +/* Temporary Files */ + +#define TMP_DIR "tmp" +#define TMP_DIR_LEN 3 + +struct tempfile { + int fh; + byte name[32]; +}; + +void open_temp(struct tempfile *, byte *); +void delete_temp(struct tempfile *); +ulg temprand(uns); + +#define TF_GENERIC "t" +#define TF_QUEUE_CONTROL "c" +#define TF_QUEUE_DATA "d" + +/* Config Files */ + +struct cfitem { + byte *name; + int type; + void *var; +}; + +#define CI_STOP 0 +#define CI_INT 1 +#define CI_STRING 2 +#define CI_FUNCTION 3 + +typedef byte *(*ci_func)(struct cfitem *, byte *); + +void cf_read(byte *, struct cfitem *); + +/* Logging */ + +#define L_DEBUG "<0>" +#define L_INFO "<2>" +#define L_WARN "<4>" +#define L_ERROR "<6>" +#define L_FATAL "<9>" + +void log(byte *, ...); +void die(byte *, ...) NONRET; +void initlog(byte *); + +/* Allocation */ + +void *xmalloc(uns); +byte *stralloc(byte *); + +/* Content-Type pattern matching */ + +int match_ct_patt(byte *, byte *); + +/* Binary log */ + +#ifdef HAVE_FFS +#define log2(x) (ffs(x) - 1) +#else +int log2(ulg); +#endif + +/* obj.c */ + +struct odes { /* Object description */ + struct oattr *attrs; +}; + +struct oattr { /* Object attribute */ + struct oattr *next, *same; + byte attr; + byte val[1]; +}; + +void obj_dump(struct odes *); +struct odes *obj_fload(FILE *); +struct odes *obj_new(void); +struct odes *obj_load(byte *); +void obj_fwrite(FILE *, struct odes *); /* Closes the file afterwards... */ +void obj_free(struct odes *); +struct oattr *find_attr(struct odes *, uns); +struct oattr *find_attr_last(struct odes *, uns); +byte *find_aval(struct odes *, uns); +struct oattr *set_attr(struct odes *, uns, byte *); +struct oattr *set_attr_num(struct odes *, uns, uns); +struct oattr *add_attr(struct odes *, struct oattr *, uns, byte *); + +/* oname.c */ + +void mk_obj_name(byte *, ulg, byte *); +FILE *create_obj_file(byte *, ulg); + +/* wordsplit.c */ + +int wordsplit(byte *, byte **, uns); + +/* patmatch.c */ + +int match_pattern(byte *, byte *); diff --git a/lib/lists.c b/lib/lists.c new file mode 100644 index 00000000..b0d611df --- /dev/null +++ b/lib/lists.c @@ -0,0 +1,74 @@ +/* + * Sherlock Library -- Linked Lists + * + * (c) 1997 Martin Mares, + */ + +#include + +#include "lists.h" + +void +add_tail(list *l, node *n) +{ + node *z = l->tail.prev; + + n->next = &l->tail; + n->prev = z; + z->next = n; + l->tail.prev = n; +} + +void +add_head(list *l, node *n) +{ + node *z = l->head.next; + + n->next = z; + n->prev = &l->head; + z->prev = n; + l->head.next = n; +} + +void +insert_node(node *n, node *after) +{ + node *z = after->next; + + n->next = z; + n->prev = after; + after->next = n; + z->prev = n; +} + +void +rem_node(node *n) +{ + node *z = n->prev; + node *x = n->next; + + z->next = x; + x->prev = z; +} + +void +init_list(list *l) +{ + l->head.next = &l->tail; + l->head.prev = NULL; + l->tail.next = NULL; + l->tail.prev = &l->head; +} + +void +add_tail_list(list *to, list *l) +{ + node *p = to->tail.prev; + node *q = l->head.next; + + p->next = q; + q->prev = p; + q = l->tail.prev; + q->next = &to->tail; + to->tail.prev = q; +} diff --git a/lib/lists.h b/lib/lists.h new file mode 100644 index 00000000..4f605697 --- /dev/null +++ b/lib/lists.h @@ -0,0 +1,98 @@ +/* + * Sherlock Library -- Linked Lists + * + * (c) 1997 Martin Mares, + */ + +struct node { + struct node *next, *prev; +}; +typedef struct node node; + +struct list { + struct node head, tail; +}; +typedef struct list list; + +#define NODE (node *) +#define HEAD(list) ((void *)((list).head.next)) +#define TAIL(list) ((void *)((list).tail.prev)) +#define DO_FOR_ALL(n,list) for((n)=HEAD(list);(NODE (n))->next; \ + n=(void *)((NODE (n))->next)) +#define EMPTY_LIST(list) (!(list).head.next->next) + +void add_tail(list *, node *); +void add_head(list *, node *); +void rem_node(node *); +void add_tail_list(list *, list *); +void init_list(list *); +void insert_node(node *, node *); + +#ifdef __GNUC__ + +extern inline void +add_tail(list *l, node *n) +{ + node *z = l->tail.prev; + + n->next = &l->tail; + n->prev = z; + z->next = n; + l->tail.prev = n; +} + +extern inline void +add_head(list *l, node *n) +{ + node *z = l->head.next; + + n->next = z; + n->prev = &l->head; + z->prev = n; + l->head.next = n; +} + +extern inline void +insert_node(node *n, node *after) +{ + node *z = after->next; + + n->next = z; + n->prev = after; + after->next = n; + z->prev = n; +} + +extern inline void +rem_node(node *n) +{ + node *z = n->prev; + node *x = n->next; + + z->next = x; + x->prev = z; +} + +extern inline void +init_list(list *l) +{ + l->head.next = &l->tail; + l->head.prev = NULL; + l->tail.next = NULL; + l->tail.prev = &l->head; +} + +extern inline void +add_tail_list(list *to, list *l) +{ + node *p = to->tail.prev; + node *q = l->head.next; + + p->next = q; + q->prev = p; + q = l->tail.prev; + q->next = &to->tail; + to->tail.prev = q; +} + +#endif diff --git a/lib/log.c b/lib/log.c new file mode 100644 index 00000000..267270aa --- /dev/null +++ b/lib/log.c @@ -0,0 +1,77 @@ +/* + * Sherlock Library -- Logging + * + * (c) 1997 Martin Mares, + */ + +#include +#include +#include +#include +#include + +#include "lib.h" + +static byte *progname = "???"; +static pid_t pid; + +static void +logit(int level, byte *msg, va_list args) +{ + time_t tim; + struct tm *tm; + char buf[32]; + + tim = time(NULL); + tm = localtime(&tim); + strftime(buf, sizeof(buf), "%d-%m-%y %H-%M-%S", tm); + fprintf(stderr, "%s %s [%d] <%d> ", buf, progname, pid, level); + vfprintf(stderr, msg, args); + fputc('\n', stderr); + fflush(stderr); +} + +void +log(byte *msg, ...) +{ + int level = 2; + va_list args; + + va_start(args, msg); + if (msg[0] == '<' && msg[1] >= '0' && msg[1] <= '9' && msg[2] == '>') + { + level = msg[1] - '0'; + msg += 3; + } + logit(level, msg, args); + va_end(args); +} + +void +die(byte *msg, ...) +{ + va_list args; + + va_start(args, msg); + logit(9, msg, args); + va_end(args); + exit(99); +} + +static byte * +basename(byte *n) +{ + byte *p = n; + + while (*n) + if (*n++ == '/') + p = n; + return p; +} + +void +initlog(byte *argv0) +{ + progname = basename(argv0); + pid = getpid(); +} diff --git a/lib/log.h b/lib/log.h new file mode 100644 index 00000000..fdd0ace2 --- /dev/null +++ b/lib/log.h @@ -0,0 +1,14 @@ +/* + * Sherlock Library -- Logging + * + * (c) 1997 Martin Mares, + */ + +#define L_DEBUG "<0>" +#define L_INFO "<2>" +#define L_WARN "<4>" +#define L_ERROR "<6>" +#define L_FATAL "<9>" + +int log(byte *, ...); +void initlog(byte *); diff --git a/lib/log2.c b/lib/log2.c new file mode 100644 index 00000000..dc0a9297 --- /dev/null +++ b/lib/log2.c @@ -0,0 +1,26 @@ +/* + * Sherlock Library -- Binary Logarithm + * + * (c) 1997 Martin Mares, + */ + +#include + +#include "lib.h" + +int +ffs(ulg x) +{ + ulg l; + + if (!x) + return 0; + + l = 0; + if (x & 0xffff0000) l += 16; + if (x & 0xff00ff00) l += 8; + if (x & 0xf0f0f0f0) l += 4; + if (x & 0xcccccccc) l += 2; + if (x & 0xaaaaaaaa) l++; + return l; +} diff --git a/lib/md5.c b/lib/md5.c new file mode 100644 index 00000000..d4f8535b --- /dev/null +++ b/lib/md5.c @@ -0,0 +1,247 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include /* for memcpy() */ +#include "md5.h" + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +void byteReverse(unsigned char *buf, unsigned longs); + +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32 t; + do { + t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *) ctx->in)[14] = ctx->bits[0]; + ((uint32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset((char *) ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32 buf[4], uint32 const in[16]) +{ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/lib/md5.h b/lib/md5.h new file mode 100644 index 00000000..53a40c27 --- /dev/null +++ b/lib/md5.h @@ -0,0 +1,22 @@ +#ifndef MD5_H +#define MD5_H + +#ifdef __alpha +typedef unsigned int uint32; +#else +typedef unsigned long uint32; +#endif + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(uint32 buf[4], uint32 const in[16]); + +#endif /* !MD5_H */ diff --git a/lib/patmatch.c b/lib/patmatch.c new file mode 100644 index 00000000..32e3df1d --- /dev/null +++ b/lib/patmatch.c @@ -0,0 +1,37 @@ +/* + * Sherlock Library -- Shell-Like Pattern Matching (currently only '?' and '*') + * + * (c) 1997 Martin Mares, + */ + +#include +#include + +#include "lib.h" + +int +match_pattern(byte *p, byte *s) +{ + while (*p) + { + if (*p == '?' && *s) + p++, s++; + else if (*p == '*') + { + int z = p[1]; + + if (!z) + return 1; + while (s = strchr(s, z)) + { + if (match_pattern(p+1, s)) + return 1; + s++; + } + return 0; + } + else if (*p++ != *s++) + return 0; + } + return !*s; +} diff --git a/lib/str_ctype.c b/lib/str_ctype.c new file mode 100644 index 00000000..fa719206 --- /dev/null +++ b/lib/str_ctype.c @@ -0,0 +1,13 @@ +/* + * Sherlock Library -- Character Classes + * + * (c) 1997 Martin Mares, + */ + +#include "string.h" + +unsigned char _c_cat[256] = { +#define CHAR(code,upper,unacc,acc,cat) cat, +#include "charmap.h" +#undef CHAR +}; diff --git a/lib/str_upper.c b/lib/str_upper.c new file mode 100644 index 00000000..2742cd4a --- /dev/null +++ b/lib/str_upper.c @@ -0,0 +1,13 @@ +/* + * Sherlock Library -- Uppercase Map + * + * (c) 1997 Martin Mares, + */ + +#include "string.h" + +unsigned char _c_upper[256] = { +#define CHAR(code,upper,unacc,acc,cat) upper, +#include "charmap.h" +#undef CHAR +}; diff --git a/lib/temp.c b/lib/temp.c new file mode 100644 index 00000000..ce9ab573 --- /dev/null +++ b/lib/temp.c @@ -0,0 +1,49 @@ +/* + * Sherlock Library -- Temporary Files + * + * (c) 1997 Martin Mares, + */ + +#include +#include +#include +#include + +#include "lib.h" + +ulg +temprand(uns key) +{ + static int seeded = 0; + ulg rand; + + if (!seeded) + { + seeded = 1; + srand(getpid()); + } + rand = random(); + rand += key * 0xdeadbeef; + return rand; +} + +void +open_temp(struct tempfile *tf, byte *tftype) +{ + int retry = 50; + while (retry--) + { + sprintf(tf->name, TMP_DIR "/%s%08x", tftype, temprand(retry)); + tf->fh = open(tf->name, O_RDWR | O_CREAT | O_EXCL, 0666); + if (tf->fh >= 0) + return; + } + die("Unable to create temporary file"); +} + +void +delete_temp(struct tempfile *tf) +{ + close(tf->fh); + unlink(tf->name); +} diff --git a/lib/url.c b/lib/url.c new file mode 100644 index 00000000..91b53efe --- /dev/null +++ b/lib/url.c @@ -0,0 +1,479 @@ +/* + * Sherlock Library -- URL Functions (according to RFC 1738 and 1808) + * + * (c) 1997 Martin Mares, + */ + +#include +#include +#include + +#include "lib.h" +#include "url.h" +#include "string.h" + +/* Escaping and de-escaping */ + +static uns +enhex(uns x) +{ + return (x<10) ? (x + '0') : (x - 10 + 'A'); +} + +int +url_deescape(byte *s, byte *d) +{ + byte *end = d + MAX_URL_SIZE - 10; + while (*s) + { + if (d >= end) + return URL_ERR_TOO_LONG; + if (*s == '%') + { + unsigned int val; + if (!Cxdigit(s[1]) || !Cxdigit(s[2])) + return URL_ERR_INVALID_ESCAPE; + val = Cxvalue(s[1])*16 + Cxvalue(s[2]); + if (!Cprint(val)) + return URL_ERR_INVALID_ESCAPED_CHAR; + switch (val) + { + case ';': + val = NCC_SEMICOLON; break; + case '/': + val = NCC_SLASH; break; + case '?': + val = NCC_QUEST; break; + case ':': + val = NCC_COLON; break; + case '@': + val = NCC_AT; break; + case '=': + val = NCC_EQUAL; break; + case '&': + val = NCC_AND; break; + } + *d++ = val; + s += 3; + } + else if (*s >= 0x20 && *s <= 0x7e) + *d++ = *s++; + else + return URL_ERR_INVALID_CHAR; + } + *d = 0; + return 0; +} + +int +url_enescape(byte *s, byte *d) +{ + byte *end = d + MAX_URL_SIZE - 10; + + while (*s) + { + if (d >= end) + return URL_ERR_TOO_LONG; + if ( *s >= 'A' && *s <= 'Z' + || *s >= 'a' && *s <= 'z' + || *s >= '0' && *s <= '9' + || *s == '$' || *s == '-' || *s == '.' || *s == '+' + || *s == '!' || *s == '*' || *s == '\'' || *s == '(' + || *s == ')' || *s == '_' || *s == ';' || *s == '/' + || *s == '?' || *s == ':' || *s == '@' || *s == '=' + || *s == '&') + *d++ = *s++; + else + { + uns val = (*s < NCC_MAX) ? ";/?:@=&"[*s] : *s; + *d++ = '%'; + *d++ = enhex(val >> 4); + *d++ = enhex(val & 0x0f); + s++; + } + } + *d = 0; + return 0; +} + +/* Split an URL (several parts may be copied to the destination buffer) */ + +uns +identify_protocol(byte *p) +{ + if (!strcasecmp(p, "http")) + return URL_PROTO_HTTP; + if (!strcasecmp(p, "ftp")) + return URL_PROTO_FTP; + return 0; +} + +int +url_split(byte *s, struct url *u, byte *d) +{ + bzero(u, sizeof(struct url)); + u->port = ~0; + u->bufend = d + MAX_URL_SIZE - 10; + + if (s[0] != '/') /* Seek for "protocol:" */ + { + byte *p = s; + while (*p && Calnum(*p)) + p++; + if (p != s && *p == ':') + { + u->protocol = d; + while (s < p) + *d++ = *s++; + *d++ = 0; + u->protoid = identify_protocol(u->protocol); + s++; + } + } + + if (s[0] == '/') /* Host spec or absolute path */ + { + if (s[1] == '/') /* Host spec */ + { + byte *q, *w, *e; + char *ep; + + s += 2; + q = d; + while (*s && *s != '/') /* Copy user:passwd@host:port */ + *d++ = *s++; + *d++ = 0; + w = strchr(q, '@'); + if (w) /* user:passwd present */ + { + *w++ = 0; + u->user = q; + } + else + w = q; + e = strchr(w, ':'); + if (e) /* host:port present */ + { + *e++ = 0; + u->port = strtoul(e, &ep, 10); + if (ep && *ep || u->port > 65535 || !u->port) + return URL_ERR_INVALID_PORT; + } + u->host = w; + } + } + + u->rest = s; + u->buf = d; + return 0; +} + +/* Normalization according to given base URL */ + +static uns std_ports[] = { ~0, 80, 21 }; /* Default port numbers */ + +static int +relpath_merge(struct url *u, struct url *b) +{ + byte *a = u->rest; + byte *o = b->rest; + byte *d = u->buf; + byte *e = u->bufend; + byte *p; + + if (a[0] == '/') /* Absolute path => OK */ + return 0; + if (o[0] != '/') + return URL_PATH_UNDERFLOW; + + if (!a[0]) /* Empty relative URL is a special case */ + { + u->rest = b->rest; + return 0; + } + + u->rest = d; + p = strrchr(o, '/'); /* Must be found! */ + while (o <= p) /* Copy original path */ + { + if (d >= e) + return URL_ERR_TOO_LONG; + *d++ = *o++; + } + + while (*a) + { + if (a[0] == '.') + { + if (a[1] == '/' || !a[1]) /* Skip "./" and ".$" */ + { + a++; + if (a[0]) + a++; + continue; + } + else if (a[1] == '.' && (a[2] == '/' || !a[2])) /* "../" */ + { + a += 2; + if (d <= u->buf + 1) + return URL_PATH_UNDERFLOW; + d--; /* Discard trailing slash */ + while (d[-1] != '/') + d--; + if (a[0]) + a++; + continue; + } + } + while (a[0] && a[0] != '/') + { + if (d >= e) + return URL_ERR_TOO_LONG; + *d++ = *a++; + } + if (a[0]) + *d++ = *a++; + } + + *d++ = 0; + u->buf = d; + return 0; +} + +int +url_normalize(struct url *u, struct url *b) +{ + byte *k; + + if (u->protocol && !u->protoid) + return 0; + + if ((u->protoid == URL_PROTO_HTTP || (!u->protoid && b && b->protoid == URL_PROTO_HTTP)) + && u->rest && (k = strchr(u->rest, '#'))) + *k = 0; /* Kill fragment reference */ + + if (u->port == ~0) + u->port = std_ports[u->protoid]; + + if ( u->protocol && !u->host + || u->host && !*u->host + || !u->host && u->user + || !u->rest) + return URL_SYNTAX_ERROR; + + if (u->protocol) /* Absolute URL */ + return 0; + + if (!b) /* Relative to something? */ + return URL_ERR_REL_NOTHING; + if (!b->protoid) + return URL_ERR_UNKNOWN_PROTOCOL; + + if (!u->protocol) + { + u->protocol = b->protocol; + u->protoid = b->protoid; + } + + if (!u->host) + { + u->host = b->host; + u->user = b->user; + u->port = b->port; + return relpath_merge(u, b); + } + + return 0; +} + +/* Name canonicalization */ + +static void +lowercase(byte *b) +{ + if (b) + while (*b) + { + if (*b >= 'A' && *b <= 'Z') + *b = *b + 0x20; + b++; + } +} + +static void +kill_end_dot(byte *b) +{ + byte *k; + + if (b) + { + k = b + strlen(b) - 1; + if (k > b && *k == '.') + *k = 0; + } +} + +int +url_canonicalize(struct url *u) +{ + lowercase(u->protocol); + lowercase(u->host); + kill_end_dot(u->host); + if ((!u->rest || !*u->rest) && (u->protoid == URL_PROTO_HTTP || u->protoid == URL_PROTO_FTP)) + u->rest = "/"; + return 0; +} + +/* Pack a broken-down URL */ + +byte * +append(byte *d, byte *s, byte *e) +{ + if (d) + while (*s) + { + if (d >= e) + return NULL; + *d++ = *s++; + } + return d; +} + +int +url_pack(struct url *u, byte *d) +{ + byte *e = d + MAX_URL_SIZE - 10; + + if (u->protocol) + { + d = append(d, u->protocol, e); + d = append(d, ":", e); + u->protoid = identify_protocol(u->protocol); + } + if (u->host) + { + d = append(d, "//", e); + if (u->user) + { + d = append(d, u->user, e); + d = append(d, "@", e); + } + d = append(d, u->host, e); + if (u->port != std_ports[u->protoid] && u->port != ~0) + { + char z[10]; + sprintf(z, "%d", u->port); + d = append(d, ":", e); + d = append(d, z, e); + } + } + if (u->rest) + d = append(d, u->rest, e); + if (!d) + return URL_ERR_TOO_LONG; + *d = 0; + return 0; +} + +/* Error messages */ + +static char *errmsg[] = { + "Something is wrong", + "Too long", + "Invalid character", + "Invalid escape", + "Invalid escaped character", + "Invalid port number", + "Relative URL not allowed", + "Unknown protocol", + "Syntax error", + "Path underflow" +}; + +char * +url_error(uns err) +{ + if (err >= sizeof(errmsg) / sizeof(char *)) + err = 0; + return errmsg[err]; +} + +/* A "macro" for canonical split */ + +int +url_canon_split(byte *u, byte *buf1, byte *buf2, struct url *url) +{ + int err; + + if (err = url_deescape(u, buf1)) + return err; + if (err = url_split(buf1, url, buf2)) + return err; + if (err = url_normalize(url, NULL)) + return err; + return url_canonicalize(url); +} + +/* Testing */ + +#ifdef TEST + +int main(int argc, char **argv) +{ + char buf1[MAX_URL_SIZE], buf2[MAX_URL_SIZE], buf3[MAX_URL_SIZE], buf4[MAX_URL_SIZE]; + int err; + struct url url, url0; + + if (argc != 2) + return 1; + if (err = url_deescape(argv[1], buf1)) + { + printf("deesc: error %d\n", err); + return 1; + } + printf("deesc: %s\n", buf1); + if (err = url_split(buf1, &url, buf2)) + { + printf("split: error %d\n", err); + return 1; + } + printf("split: @%s@%s@%s@%d@%s\n", url.protocol, url.user, url.host, url.port, url.rest); + if (err = url_split("http://mj@www.hell.org/123/sub_dir/index.html", &url0, buf3)) + { + printf("split base: error %d\n", err); + return 1; + } + if (err = url_normalize(&url0, NULL)) + { + printf("normalize base: error %d\n", err); + return 1; + } + printf("base: @%s@%s@%s@%d@%s\n", url0.protocol, url0.user, url0.host, url0.port, url0.rest); + if (err = url_normalize(&url, &url0)) + { + printf("normalize: error %d\n", err); + return 1; + } + printf("normalize: @%s@%s@%s@%d@%s\n", url.protocol, url.user, url.host, url.port, url.rest); + if (err = url_canonicalize(&url)) + { + printf("canonicalize: error %d\n", err); + return 1; + } + printf("canonicalize: @%s@%s@%s@%d@%s\n", url.protocol, url.user, url.host, url.port, url.rest); + if (err = url_pack(&url, buf4)) + { + printf("pack: error %d\n", err); + return 1; + } + printf("pack: %s\n", buf1); + if (err = url_enescape(buf4, buf2)) + { + printf("enesc: error %d\n", err); + return 1; + } + printf("enesc: %s\n", buf2); + return 0; +} + +#endif diff --git a/lib/url.h b/lib/url.h new file mode 100644 index 00000000..df1ad76f --- /dev/null +++ b/lib/url.h @@ -0,0 +1,63 @@ +/* + * Sherlock Library -- URL Functions + * + * (c) 1997 Martin Mares, + */ + +#define MAX_URL_SIZE 1024 + +/* Non-control meanings of control characters */ + +#define NCC_SEMICOLON 1 +#define NCC_SLASH 2 +#define NCC_QUEST 3 +#define NCC_COLON 4 +#define NCC_AT 5 +#define NCC_EQUAL 6 +#define NCC_AND 7 +#define NCC_MAX 8 + +/* Remove/Introduce '%' escapes */ + +int url_deescape(byte *, byte *); +int url_enescape(byte *, byte *); + +/* URL splitting and normalization */ + +struct url { + byte *protocol; + uns protoid; + byte *user; + byte *host; + uns port; /* ~0 if unspec */ + byte *rest; + byte *buf, *bufend; +}; + +int url_split(byte *, struct url *, byte *); +int url_normalize(struct url *, struct url *); +int url_canonicalize(struct url *); +int url_pack(struct url *, byte *); +int url_canon_split(byte *, byte *, byte *, struct url *); +uns identify_protocol(byte *); + +/* Error codes */ + +char *url_error(uns); + +#define URL_ERR_TOO_LONG 1 +#define URL_ERR_INVALID_CHAR 2 +#define URL_ERR_INVALID_ESCAPE 3 +#define URL_ERR_INVALID_ESCAPED_CHAR 4 +#define URL_ERR_INVALID_PORT 5 +#define URL_ERR_REL_NOTHING 6 +#define URL_ERR_UNKNOWN_PROTOCOL 7 +#define URL_SYNTAX_ERROR 8 +#define URL_PATH_UNDERFLOW 9 + +#define URL_PROTO_UNKNOWN 0 +#define URL_PROTO_HTTP 1 +#define URL_PROTO_FTP 2 +#define URL_PROTO_MAX 3 + +#define URL_PNAMES { "unknown", "http", "ftp" } diff --git a/lib/wordsplit.c b/lib/wordsplit.c new file mode 100644 index 00000000..b1b2ada3 --- /dev/null +++ b/lib/wordsplit.c @@ -0,0 +1,30 @@ +/* + * Sherlock Library -- Word Splitting + * + * (c) 1997 Martin Mares, + */ + +#include + +#include "lib.h" +#include "string.h" + +int +wordsplit(byte *src, byte **dst, uns max) +{ + int cnt = 0; + + for(;;) + { + while (Cspace(*src)) + *src++ = 0; + if (!*src) + break; + if (cnt >= max) + return -1; + dst[cnt++] = src; + while (*src && !Cspace(*src)) + src++; + } + return cnt; +} -- 2.39.2