From b30fd7b756a0664c4e1fef3e936d9aab13c0d6fe Mon Sep 17 00:00:00 2001 From: ian Date: Thu, 29 Aug 2002 00:36:25 +0000 Subject: [PATCH] Builds a working plugin. --- base/chiark-tcl.h | 74 ++++++++++++++++++ base/enum.c | 54 +++++++++++++ base/troglodyte-Makefile | 23 +++--- hbytes/hbytes.c | 165 +++++++++++++++++++++++++++++++++++++++ hbytes/hbytes.h | 74 ++++++++++++++++++ 5 files changed, 378 insertions(+), 12 deletions(-) create mode 100644 base/chiark-tcl.h create mode 100644 base/enum.c create mode 100644 hbytes/hbytes.c create mode 100644 hbytes/hbytes.h diff --git a/base/chiark-tcl.h b/base/chiark-tcl.h new file mode 100644 index 0000000..5aca162 --- /dev/null +++ b/base/chiark-tcl.h @@ -0,0 +1,74 @@ +/* + */ +/* + * + * hbytes bin VAR => binary string + * hbytes bin VAR VALUE => set + * + * hbytes prefix VAR [VALUE ...] = set VAR [concat VALUE ... $VAR] + * hbytes append VAR [VALUE ...] = set VAR [concat $VAR VALUE ...] + * hbytes concat VAR [VALUE ...] = set VAR [concat VALUE ...] + * hbytes unprepend VAR PREFIXLENGTH => prefix (removed from VAR) + * hbytes unappend VAR SUFFIXLENGTH => suffix (removed from VAR) + * hbytes chopto VAR NEWVARLENGTH => suffix (removed from VAR) + * (too short? error) + * + * hbytes pkcs5 pv|uv VAR ALG => worked? (always 1 for p) + * hbytes pkcs5 pn|un VAR BLOCKSIZE => worked? (always 1 for p) + * hbytes blockcipher e|d VAR ALG MODE [IV] => IV + * hbytes hash ALG VALUE => hash + * hbytes hmac ALG VALUE KEY [MACLENGTH] => mac + * + * Refs: HMAC: RFC2104 + */ + +#ifndef HBYTES_H +#define HBYTES_H + +#include +#include + +#include + +typedef unsigned char Byte; + +/* from hbytes.c */ + +typedef struct { + Byte *start, *end; /* always allocated dynamically */ +} HBytes_Value; /* overlays internalRep */ + +extern Tcl_ObjType hbytes_type; + +int staticerr(Tcl_Interp *ip, const char *m); +void objfreeir(Tcl_Obj *o); + +Tcl_Obj *hbytes_set(Tcl_Obj *overwrite, const Byte *array, int l); + +/* from enum.c */ + +extern Tcl_ObjType enum_nearlytype; + +const void *enum_lookup_cached_func(Tcl_Interp *ip, Tcl_Obj *o, + size_t entrysize, const void *firstentry, + const char *what); +#define enum_lookup_cached(ip,o,table,what) \ + (enum_lookup_cached_func((ip),(o), \ + sizeof((table)[0]),&(table)[0], \ + (what))) + /* table should be a pointer to an array of structs of size + * entrysize, the first member of which should be a const char*. + * The table should finish with a null const char *. + * On error, 0 is returned and the ip->result will have been + * set to the error message. + */ + +/* useful macros */ + +#define HBYTES(o) ((HBytes_Value*)&(o)->internalRep.twoPtrValue) +#define HBYTES_LEN(o) (HBYTES((o))->end - HBYTES((o))->start) + +#define TALLOC(s) ((void*)Tcl_Alloc((s))) +#define TFREE(f) (Tcl_Free((void*)(f))) + +#endif /*HBYTES_H*/ diff --git a/base/enum.c b/base/enum.c new file mode 100644 index 0000000..1a66aa3 --- /dev/null +++ b/base/enum.c @@ -0,0 +1,54 @@ +/* + * + */ + +#include "hbytes.h" + +static void enum_nt_dup(Tcl_Obj *src, Tcl_Obj *dup) { + dup->internalRep= src->internalRep; +} + +static void enum_nt_ustr(Tcl_Obj *o) { + abort(); +} + +static int enum_nt_sfa(Tcl_Interp *ip, Tcl_Obj *o) { + abort(); +} + +Tcl_ObjType enum_nearlytype = { + "enum-nearly", + 0, enum_nt_dup, enum_nt_ustr, enum_nt_sfa +}; + +const void *enum_lookup_cached_func(Tcl_Interp *ip, Tcl_Obj *o, + size_t entrysize, const void *firstentry, + const char *what) { + const char *supplied, *found; + const char *ep; + + if (o->typePtr == &enum_nearlytype && + o->internalRep.twoPtrValue.ptr1 == firstentry) + return o->internalRep.twoPtrValue.ptr2; + + supplied= Tcl_GetStringFromObj(o,0); assert(supplied); + for (ep= firstentry; + (found= *(const char*const*)ep) && strcmp(supplied,found); + ep += entrysize); + + if (found) { + objfreeir(o); + o->typePtr= &enum_nearlytype; + o->internalRep.twoPtrValue.ptr1= (void*)firstentry; + o->internalRep.twoPtrValue.ptr2= (void*)ep; + return ep; + } + + Tcl_ResetResult(ip); + Tcl_AppendResult(ip, "invalid ",what," - must be one of:",(char*)0); + for (ep= firstentry; + (found= *(const char*const*)ep); + ep += entrysize) + Tcl_AppendResult(ip, " ",found,(char*)0); + return 0; +} diff --git a/base/troglodyte-Makefile b/base/troglodyte-Makefile index 2ae36d5..765d5e4 100644 --- a/base/troglodyte-Makefile +++ b/base/troglodyte-Makefile @@ -1,20 +1,19 @@ -OBJS= forwarder.o \ - main.o \ - misc.o \ - intr-sigio.o \ - bget/bget.o +OBJS= hbytes.o \ + enum.o -HDRS= misc.h \ - forwarder.h \ - intr.h +HDRS= hbytes.h -CFLAGS= -g -Wall +TARGETS= hbytes.so -fvpn: $(OBJS) - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) +CFLAGS= -g -Wall -O + +all: $(TARGETS) + +hbytes.so: $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ -shared $(OBJS) $(LDLIBS) %.o: %.c $(HDRS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< clean: - rm -f $(OBJS) *~ ./#*# + rm -f $(OBJS) $(TARGETS) *~ ./#*# diff --git a/hbytes/hbytes.c b/hbytes/hbytes.c new file mode 100644 index 0000000..99bddfe --- /dev/null +++ b/hbytes/hbytes.c @@ -0,0 +1,165 @@ +/* + * + */ + +#include "hbytes.h" + +int staticerr(Tcl_Interp *ip, const char *m) { + Tcl_SetResult(ip, (char*)m, TCL_STATIC); + return TCL_ERROR; +} + +static void hbytes_setintern(Tcl_Obj *o, const Byte *array, int l) { + Byte *np; + + HBYTES(o)->start= np= l ? TALLOC(l) : 0; + memcpy(np, array, l); + HBYTES(o)->end= np + l; + o->typePtr = &hbytes_type; +} + +static void hbytes_t_dup(Tcl_Obj *src, Tcl_Obj *dup) { + hbytes_setintern(src, HBYTES(src)->start, HBYTES_LEN(src)); +} + +Tcl_Obj *hbytes_set(Tcl_Obj *overwrite, const Byte *array, int l) { + if (!overwrite) overwrite= Tcl_NewObj(); + objfreeir(overwrite); + Tcl_InvalidateStringRep(overwrite); + hbytes_setintern(overwrite, array, l); + return overwrite; +} + +static void hbytes_t_free(Tcl_Obj *o) { + TFREE(HBYTES(o)->start); +} + +static void hbytes_t_ustr(Tcl_Obj *o) { + int l; + char *str; + const Byte *byte; + + l= HBYTES_LEN(o); + byte= HBYTES(o)->start; + str= o->bytes= TALLOC(l*2+1); + o->length= l*2; + while (l>0) { + sprintf(str,"%02x",*byte); + str+=2; byte++; l--; + } +} + +void objfreeir(Tcl_Obj *o) { + if (o->typePtr && o->typePtr->freeIntRepProc) + o->typePtr->freeIntRepProc(o); +} + +static int hbytes_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) { + char *str, *ep, *os; + Byte *startbytes, *bytes; + int l; + char cbuf[3]; + + os= str= Tcl_GetStringFromObj(o,&l); assert(str); + if (l & 1) return staticerr(ip, "hbytes: conversion from hex:" + " odd length in hex"); + + startbytes= bytes= l ? TALLOC(l*2) : 0; + cbuf[2]= 0; + while (l>0) { + cbuf[0]= *str++; + cbuf[1]= *str++; + *bytes++= strtoul(cbuf,&ep,16); + if (ep != cbuf+2) { + TFREE(startbytes); +fprintf(stderr,">%d|%s|%s<\n",l,os,cbuf); + return staticerr(ip, "hbytes: conversion from hex:" + " bad hex digit"); + } + l -= 2; + } + objfreeir(o); + + HBYTES(o)->start= startbytes; + HBYTES(o)->end= bytes; + o->typePtr = &hbytes_type; + return TCL_OK; +} + +Tcl_ObjType hbytes_type = { + "hbytes", + hbytes_t_free, hbytes_t_dup, hbytes_t_ustr, hbytes_t_sfa +}; + +static Tcl_Obj *hb_getvar(Tcl_Interp *ip, Tcl_Obj *varname) { + int ec; + Tcl_Obj *value; + + value= Tcl_ObjGetVar2(ip,varname,0,TCL_LEAVE_ERR_MSG); + if (!value) return 0; + + ec= Tcl_ConvertToType(ip,value,&hbytes_type); + if (ec) return 0; + + return value; +} + +static int hc_bin(ClientData cd, Tcl_Interp *ip, int objc, + Tcl_Obj *const *objv) { + Tcl_Obj *varname, *value, *result; + const char *str; + int l; + + varname= objv[0]; + switch (objc) { + case 1: + value= hb_getvar(ip,varname); if (!value) return TCL_ERROR; + result= Tcl_NewStringObj(HBYTES(value)->start, HBYTES_LEN(value)); + assert(result); + Tcl_SetObjResult(ip,result); + return TCL_OK; + case 2: + value= objv[1]; + str= Tcl_GetStringFromObj(value,&l); + value= hbytes_set(0,str,l); + value= Tcl_ObjSetVar2(ip,varname,0, value, TCL_LEAVE_ERR_MSG); + if (!value) return TCL_ERROR; + Tcl_ResetResult(ip); + return TCL_OK; + } + abort(); +} + +typedef struct { + const char *name; + int minargs, maxargs; + Tcl_ObjCmdProc *func; +} SubCommand; + +static const SubCommand subcommands[] = { + { "bin", 1, 2, hc_bin }, + { 0 } +}; + +static int hb_proc(ClientData cd, Tcl_Interp *ip, int objc, + Tcl_Obj *const *objv) { + const SubCommand *sc; + + if (objc<2) return staticerr(ip, "hbytes: need subcommand"); + sc= enum_lookup_cached(ip,objv[1],subcommands,"hbytes subcommand"); + if (!sc) return TCL_ERROR; + objc -= 2; + objv += 2; + if (objc < sc->minargs) + return staticerr(ip, "too few args"); + if (sc->maxargs >=0 && objc > sc->maxargs) + return staticerr(ip,"too many args"); + return sc->func((void*)sc,ip,objc,objv); +} + +int Hbytes_Init(Tcl_Interp *ip) { + Tcl_RegisterObjType(&hbytes_type); + Tcl_RegisterObjType(&enum_nearlytype); + Tcl_CreateObjCommand(ip,"hbytes", hb_proc,0,0); + return TCL_OK; +} diff --git a/hbytes/hbytes.h b/hbytes/hbytes.h new file mode 100644 index 0000000..5aca162 --- /dev/null +++ b/hbytes/hbytes.h @@ -0,0 +1,74 @@ +/* + */ +/* + * + * hbytes bin VAR => binary string + * hbytes bin VAR VALUE => set + * + * hbytes prefix VAR [VALUE ...] = set VAR [concat VALUE ... $VAR] + * hbytes append VAR [VALUE ...] = set VAR [concat $VAR VALUE ...] + * hbytes concat VAR [VALUE ...] = set VAR [concat VALUE ...] + * hbytes unprepend VAR PREFIXLENGTH => prefix (removed from VAR) + * hbytes unappend VAR SUFFIXLENGTH => suffix (removed from VAR) + * hbytes chopto VAR NEWVARLENGTH => suffix (removed from VAR) + * (too short? error) + * + * hbytes pkcs5 pv|uv VAR ALG => worked? (always 1 for p) + * hbytes pkcs5 pn|un VAR BLOCKSIZE => worked? (always 1 for p) + * hbytes blockcipher e|d VAR ALG MODE [IV] => IV + * hbytes hash ALG VALUE => hash + * hbytes hmac ALG VALUE KEY [MACLENGTH] => mac + * + * Refs: HMAC: RFC2104 + */ + +#ifndef HBYTES_H +#define HBYTES_H + +#include +#include + +#include + +typedef unsigned char Byte; + +/* from hbytes.c */ + +typedef struct { + Byte *start, *end; /* always allocated dynamically */ +} HBytes_Value; /* overlays internalRep */ + +extern Tcl_ObjType hbytes_type; + +int staticerr(Tcl_Interp *ip, const char *m); +void objfreeir(Tcl_Obj *o); + +Tcl_Obj *hbytes_set(Tcl_Obj *overwrite, const Byte *array, int l); + +/* from enum.c */ + +extern Tcl_ObjType enum_nearlytype; + +const void *enum_lookup_cached_func(Tcl_Interp *ip, Tcl_Obj *o, + size_t entrysize, const void *firstentry, + const char *what); +#define enum_lookup_cached(ip,o,table,what) \ + (enum_lookup_cached_func((ip),(o), \ + sizeof((table)[0]),&(table)[0], \ + (what))) + /* table should be a pointer to an array of structs of size + * entrysize, the first member of which should be a const char*. + * The table should finish with a null const char *. + * On error, 0 is returned and the ip->result will have been + * set to the error message. + */ + +/* useful macros */ + +#define HBYTES(o) ((HBytes_Value*)&(o)->internalRep.twoPtrValue) +#define HBYTES_LEN(o) (HBYTES((o))->end - HBYTES((o))->start) + +#define TALLOC(s) ((void*)Tcl_Alloc((s))) +#define TFREE(f) (Tcl_Free((void*)(f))) + +#endif /*HBYTES_H*/ -- 2.30.2