diff options
| author | Magnus Auvinen <magnus.auvinen@gmail.com> | 2008-02-24 16:03:58 +0000 |
|---|---|---|
| committer | Magnus Auvinen <magnus.auvinen@gmail.com> | 2008-02-24 16:03:58 +0000 |
| commit | 4739966e14ca2df24d4f44fb814b6275b9bf2a3c (patch) | |
| tree | 2398dee3380dfa48582a71a4f2d4278448fa6cb8 /scripts/netobj.py | |
| parent | 1ea859c431b33a384727c0016917dde15bceeff3 (diff) | |
| download | zcatch-4739966e14ca2df24d4f44fb814b6275b9bf2a3c.tar.gz zcatch-4739966e14ca2df24d4f44fb814b6275b9bf2a3c.zip | |
larger restructure to improve security
Diffstat (limited to 'scripts/netobj.py')
| -rw-r--r-- | scripts/netobj.py | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/scripts/netobj.py b/scripts/netobj.py new file mode 100644 index 00000000..107f49c4 --- /dev/null +++ b/scripts/netobj.py @@ -0,0 +1,270 @@ +import sys, os + +line_count = 0 + +class variable: + name = "unknown" + def __init__(self, args, name): + global line_count + self.name = name + self.line = line_count + def emit_declaration(self): + return ["\tint %s;" % self.name] + def linedef(self): + return "#line %d" % self.line + def emit_secure(self): + return [] + +class var_any(variable): + def __init__(self, args, name): + variable.__init__(self, args, name) + +class var_range(variable): + def __init__(self, args, name): + variable.__init__(self, args, name) + self.min = args[0] + self.max = args[1] + def emit_secure(self): + return [self.linedef(), "obj->%s = netobj_clamp_int(obj->%s, %s, %s);" % (self.name, self.name, self.min, self.max)] + +class var_clientid(variable): + def __init__(self, args, name): + variable.__init__(self, args, name) + def emit_secure(self): + return [self.linedef(), "obj->%s = netobj_clamp_int(obj->%s, -1, MAX_CLIENTS);" % (self.name, self.name)] + +class var_string(variable): + def __init__(self, args, name): + variable.__init__(self, args, name) + +class object: + def __init__(self, line): + fields = line.split() + self.name = fields[1] + self.extends = None + if len(fields) == 4 and fields[2] == "extends": + self.extends = fields[3] + self.enum_name = "NETOBJTYPE_%s" % self.name.upper() + self.struct_name = "NETOBJ_%s" % self.name.upper() + self.members = [] + + def parse(self, lines): + global line_count + for index in xrange(0, len(lines)): + line_count += 1 + line = lines[index] + if not len(line): + continue + + if line == "end": + return lines[index+1:] + else: + # check for argument + fields = line.split(")", 1) + if len(fields) == 2: + names = [line.strip() for line in fields[1].split(",")] + l = fields[0].split("(", 1) + type = l[0] + args = [line.strip() for line in l[1].split(",")] + else: + l = fields[0].split(None, 1) + type = l[0] + args = [] + names = [line.strip() for line in l[1].split(",")] + + for name in names: + create_string = 'var_%s(%s, "%s")' % (type, args, name) + new_member = eval(create_string) + self.members += [new_member] + + raise BaseException("Parse error") + + def emit_declaration(self): + lines = [] + if self.extends: + lines += ["struct %s : public NETOBJ_%s\n {" % (self.struct_name, self.extends.upper())] + else: + lines += ["struct %s\n {" % self.struct_name] + for m in self.members: + lines += m.emit_declaration() + lines += ["};"] + return lines + + def emit_secure(self): + lines = [] + for m in self.members: + lines += m.emit_secure() + return lines + +class event(object): + def __init__(self, line): + object.__init__(self, line) + self.enum_name = "NETEVENTTYPE_%s" % self.name.upper() + self.struct_name = "NETEVENT_%s" % self.name.upper() + +class raw_reader: + def __init__(self): + self.raw_lines = [] + def parse(self, lines): + global line_count + for index in xrange(0, len(lines)): + line_count += 1 + line = lines[index] + if not len(line): + continue + + if line == "end": + return lines[index+1:] + else: + self.raw_lines += [line] + + raise BaseException("Parse error") + +class proto: + def __init__(self): + self.objects = [] + self.source_raw = [] + self.header_raw = [] + + +def load(filename): + # read the file + global line_count + line_count = 0 + lines = [line.strip() for line in file(filename).readlines()] + + p = proto() + + while len(lines): + line_count += 1 + line = lines[0] + line = line.split("//", 2)[0] # strip comment + + if not len(line): + del lines[0] + continue + + fields = line.split(None, 1) + + del lines[0] + + if fields[0] == "object" or fields[0] == "msg": + new_obj = object(line) + lines = new_obj.parse(lines) + p.objects += [new_obj] + elif fields[0] == "event": + new_obj = event(line) + lines = new_obj.parse(lines) + p.objects += [new_obj] + elif fields[0] == "raw_source": + raw = raw_reader() + lines = raw.parse(lines) + p.source_raw += raw.raw_lines + elif fields[0] == "raw_header": + raw = raw_reader() + lines = raw.parse(lines) + p.header_raw += raw.raw_lines + else: + print "error, strange line:", line + + return p + +def emit_header_file(f, p): + for l in p.header_raw: + print >>f, l + + if 1: # emit the enum table + print >>f, "enum {" + print >>f, "\tNETOBJTYPE_INVALID=0," + for obj in p.objects: + print >>f, "\t%s," % obj.enum_name + print >>f, "\tNUM_NETOBJTYPES" + print >>f, "};" + print >>f, "" + + print >>f, "int netobj_secure(int type, void *data, int size);" + print >>f, "const char *netobj_get_name(int type);" + print >>f, "" + + for obj in p.objects: + for l in obj.emit_declaration(): + print >>f, l + print >>f, "" + +def emit_source_file(f, p, protofilename): + + + print >>f, "#line 1 \"%s\"" % os.path.abspath(protofilename) + + for l in p.source_raw: + print >>f, l + + print >>f, "static int netobj_clamp_int(int v, int min, int max)" + print >>f, "{" + print >>f, "if(v<min) return min;" + print >>f, "if(v>max) return max;" + print >>f, "return v;" + print >>f, "}" + print >>f, "" + + if 1: # names + print >>f, "static const char *object_names[] = {" + print >>f, "\t" + '"invalid",' + for obj in p.objects: + print >>f, '\t"%s",' % obj.name + print >>f, '\t""' + print >>f, "};" + print >>f, "" + + if 1: # secure functions + print >>f, "static int secure_object_invalid(void *data, int size) { return 0; }" + for obj in p.objects: + print >>f, "static int secure_%s(void *data, int size)" % obj.name + print >>f, "{" + print >>f, "\t%s *obj = (%s *)data;" % (obj.struct_name, obj.struct_name) + print >>f, "\t(void)obj;" # to get rid of "unused variable" warning + print >>f, "\tif(size != sizeof(%s)) return -1;" % obj.struct_name + if obj.extends: + print >>f, "\tif(secure_%s(data, sizeof(NETOBJ_%s)) != 0) return -1;" % (obj.extends, obj.extends.upper()) + + for l in obj.emit_secure(): + print >>f, "\t" + l + print >>f, "\treturn 0;"; + print >>f, "}" + print >>f, "" + + if 1: # secure function table + print >>f, "typedef static int(*SECUREFUNC)(void *data, int size);" + print >>f, "static SECUREFUNC secure_funcs[] = {" + print >>f, "\t" + 'secure_object_invalid,' + for obj in p.objects: + print >>f, "\tsecure_%s," % obj.name + print >>f, "\t" + '0x0' + print >>f, "};" + print >>f, "" + + if 1: + print >>f, "int netobj_secure(int type, void *data, int size)" + print >>f, "{" + print >>f, "\tif(type < 0 || type >= NUM_NETOBJTYPES) return -1;" + print >>f, "\treturn secure_funcs[type](data, size);" + print >>f, "};" + print >>f, "" + + if 1: + print >>f, "const char *netobj_get_name(int type)" + print >>f, "{" + print >>f, "\tif(type < 0 || type >= NUM_NETOBJTYPES) return \"(invalid)\";" + print >>f, "\treturn object_names[type];" + print >>f, "};" + print >>f, "" + +if sys.argv[1] == "header": + p = load(sys.argv[2]) + emit_header_file(file(sys.argv[3], "w"), p) +elif sys.argv[1] == "source": + p = load(sys.argv[2]) + emit_source_file(file(sys.argv[3], "w"), p, sys.argv[2]) +else: + print "invalid command" + sys.exit(-1) |