package jail // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // // void set_iov_field(struct iovec *iov, int field, void *val, size_t len) { // iov[field].iov_base = val; // iov[field].iov_len = len; // } // // void *get_iov_field(struct iovec *iov, int field, size_t *len) { // *len = iov[field].iov_len; // return iov[field].iov_base; // } // // void print_iov(struct iovec *iov, int niov) { // for (int i = 0; i < niov; i++) { // if (iov[i].iov_base == NULL) // fprintf(stderr, "(NULL), %lu\n", iov[i].iov_len); // else // fprintf(stderr, "%s, %lu\n", iov[i].iov_base, iov[i].iov_len); // } // } // // void set_int_val(int *dst, int src) { // *dst = src; // } // // int get_errno() { // return errno; // } // // struct in_addr *get_in_addr_ptr(struct in_addr *a, int idx) { // return &a[idx]; // } // // struct in6_addr *get_in6_addr_ptr(struct in6_addr *a, int idx) { // return &a[idx]; // } import "C" import ( "errors" "fmt" "unsafe" ) const ( JAIL_CREATE = C.JAIL_CREATE JAIL_UPDATE = C.JAIL_UPDATE JAIL_ATTACH = C.JAIL_ATTACH JAIL_DYING = C.JAIL_DYING JAIL_SYS_DISABLE = C.JAIL_SYS_DISABLE JAIL_SYS_NEW = C.JAIL_SYS_NEW JAIL_SYS_INHERIT = C.JAIL_SYS_INHERIT JAIL_API_VERSION = C.JAIL_API_VERSION ) var EPerm = errors.New(C.GoString(C.strerror(C.EPERM))) var EFault = errors.New(C.GoString(C.strerror(C.EFAULT))) var EInval = errors.New(C.GoString(C.strerror(C.EINVAL))) var EAgain = errors.New(C.GoString(C.strerror(C.EAGAIN))) var ENoent = errors.New(C.GoString(C.strerror(C.ENOENT))) var EExist = errors.New(C.GoString(C.strerror(C.EEXIST))) var ENameTooLong = errors.New(C.GoString(C.strerror(C.ENAMETOOLONG))) type Jail struct { Version int32 Path string Hostname string Jailname string Ip4s []string Ip6s []string } func (j Jail) Jail() (int, error) { var jid int = 0 var err error = nil c_jail := (*C.struct_jail)(C.malloc(C.sizeof_struct_jail)) c_jail.version = C.uint32_t(j.Version) c_jail.path = C.CString(j.Path) c_jail.hostname = C.CString(j.Hostname) c_jail.jailname = C.CString(j.Jailname) c_jail.ip4s = C.uint32_t(len(j.Ip4s)) c_jail.ip6s = C.uint32_t(len(j.Ip6s)) if c_jail.ip4s > 0 { ip4 := (*C.struct_in_addr)(C.malloc(C.ulong(C.sizeof_struct_in_addr * c_jail.ip4s))) for i, ip := range j.Ip4s { c_str := C.CString(ip) ptr := C.get_in_addr_ptr((*C.struct_in_addr)(ip4), C.int(i)) if C.inet_pton(C.AF_INET, c_str, unsafe.Pointer(ptr)) == -1 { panic("Invalid IPv4 address") } C.free(unsafe.Pointer(c_str)) } c_jail.ip4 = ip4 } else { c_jail.ip4 = (*C.struct_in_addr)(C.NULL) } if c_jail.ip6s > 0 { ip6 := (*C.struct_in6_addr)(C.malloc(C.ulong(C.sizeof_struct_in6_addr * c_jail.ip6s))) for i, ip := range j.Ip6s { c_str := C.CString(ip) ptr := C.get_in6_addr_ptr((*C.struct_in6_addr)(ip6), C.int(i)) if C.inet_pton(C.AF_INET6, c_str, unsafe.Pointer(ptr)) == -1 { panic("Invalid IPv6 address") } C.free(unsafe.Pointer(c_str)) } c_jail.ip6 = ip6 } else { c_jail.ip6 = (*C.struct_in6_addr)(C.NULL) } ret := C.jail(c_jail) if ret == -1 { err = errnoToError() goto do_free } jid = int(ret) do_free: C.free(unsafe.Pointer(c_jail.path)) C.free(unsafe.Pointer(c_jail.hostname)) C.free(unsafe.Pointer(c_jail.jailname)) C.free(unsafe.Pointer(c_jail.ip4)) C.free(unsafe.Pointer(c_jail.ip6)) C.free(unsafe.Pointer(c_jail)) return jid, err } func mapToIov(params map[string]interface{}) (unsafe.Pointer, int, []unsafe.Pointer) { var freeList []unsafe.Pointer var i = 0 iov := C.malloc(C.ulong(C.sizeof_struct_iovec * C.int(len(params)*2))) freeList = append(freeList, iov) for k, v := range params { c_key := C.CString(k) freeList = append(freeList, unsafe.Pointer(c_key)) C.set_iov_field((*C.struct_iovec)(iov), C.int(i), unsafe.Pointer(c_key), C.strlen(c_key)+1) i++ if k == "ip4.addr" { if v_ip, ok := v.(string); ok { ip := C.malloc(C.sizeof_struct_in_addr) freeList = append(freeList, ip) c_str := C.CString(v_ip) if C.inet_pton(C.AF_INET, c_str, ip) == -1 { panic("Invalid IPv4 address") } C.free(unsafe.Pointer(c_str)) C.set_iov_field((*C.struct_iovec)(iov), C.int(i), ip, C.sizeof_struct_in_addr) } else if v_a, ok := v.([]string); ok { ips := C.malloc(C.ulong(C.sizeof_struct_in_addr * len(v_a))) freeList = append(freeList, ips) for i, ip := range v_a { c_str := C.CString(ip) ptr := C.get_in_addr_ptr((*C.struct_in_addr)(ips), C.int(i)) if C.inet_pton(C.AF_INET, c_str, unsafe.Pointer(ptr)) == -1 { panic("Invalid IPv4 address") } C.free(unsafe.Pointer(c_str)) } C.set_iov_field((*C.struct_iovec)(iov), C.int(i), ips, C.ulong(C.sizeof_struct_in_addr*len(v_a))) } else { panic("Unknown IPv4 type") } } else if k == "ip6.addr" { if v_ip, ok := v.(string); ok { ip := C.malloc(C.sizeof_struct_in6_addr) freeList = append(freeList, ip) c_str := C.CString(v_ip) if C.inet_pton(C.AF_INET6, c_str, ip) == -1 { panic("Invalid IPv6 address") } C.free(unsafe.Pointer(c_str)) C.set_iov_field((*C.struct_iovec)(iov), C.int(i), ip, C.sizeof_struct_in6_addr) } else if v_a, ok := v.([]string); ok { ips := C.malloc(C.ulong(C.sizeof_struct_in6_addr * len(v_a))) freeList = append(freeList, ips) for i, ip := range v_a { c_str := C.CString(ip) ptr := C.get_in6_addr_ptr((*C.struct_in6_addr)(ips), C.int(i)) if C.inet_pton(C.AF_INET6, c_str, unsafe.Pointer(ptr)) == -1 { panic("Invalid IPv6 address") } C.free(unsafe.Pointer(c_str)) } C.set_iov_field((*C.struct_iovec)(iov), C.int(i), ips, C.ulong(C.sizeof_struct_in6_addr*len(v_a))) } else { panic("Unknown IPv6 type") } } else if v_i, ok := v.(int); ok { c_val := C.malloc(C.sizeof_int) freeList = append(freeList, unsafe.Pointer(c_val)) C.set_int_val((*C.int)(c_val), C.int(v_i)) C.set_iov_field((*C.struct_iovec)(iov), C.int(i), c_val, C.sizeof_int) } else if v_s, ok := v.(string); ok { c_val := C.CString(v_s) freeList = append(freeList, unsafe.Pointer(c_val)) C.set_iov_field((*C.struct_iovec)(iov), C.int(i), unsafe.Pointer(c_val), C.strlen(c_val)+1) } else if _, ok := v.(bool); ok { C.set_iov_field((*C.struct_iovec)(iov), C.int(i), unsafe.Pointer(nil), C.ulong(0)) } else { panic("Unknown type") } i++ } return iov, len(params) * 2, freeList } func iovToMap(iov unsafe.Pointer, niov int, params map[string]interface{}) { for i := 0; i < len(params)*2; i += 2 { var key *C.char var key_len C.ulong var val unsafe.Pointer var val_len C.ulong key = (*C.char)(C.get_iov_field((*C.struct_iovec)(iov), C.int(i+0), &key_len)) val = C.get_iov_field((*C.struct_iovec)(iov), C.int(i+1), &val_len) go_key := C.GoString(key) if v, ok := params[go_key]; ok { if _, ok := v.(int); ok { params[go_key] = int(*(*C.int)(val)) } else if _, ok := v.(string); ok { params[go_key] = C.GoString((*C.char)(val)) } else if _, ok := v.(bool); ok { // XXX: noop for now } else { panic("Got unknown type from kernel") } } else { panic(fmt.Sprintf("Got unknown key from kernel: %v", go_key)) } } } func freeIov(freeList []unsafe.Pointer) { for _, e := range freeList { C.free(e) } } func errnoToError() error { errno := C.get_errno() if errno == C.EPERM { return EPerm } else if errno == C.EFAULT { return EFault } else if errno == C.EINVAL { return EInval } else if errno == C.EAGAIN { return EAgain } else if errno == C.ENOENT { return ENoent } else if errno == C.EEXIST { return EExist } else if errno == C.ENAMETOOLONG { return ENameTooLong } else { return errors.New("Unknown error") } } func Set(params map[string]interface{}, flags int) (int, error) { iov, niov, freeList := mapToIov(params) defer freeIov(freeList) ret := C.jail_set((*C.struct_iovec)(iov), C.uint(niov), C.int(flags)) if ret == -1 { return 0, errnoToError() } return int(ret), nil } func Get(params map[string]interface{}, flags int) (int, error) { iov, niov, freeList := mapToIov(params) defer freeIov(freeList) ret := C.jail_get((*C.struct_iovec)(iov), C.uint(niov), C.int(flags)) if ret == -1 { return 0, errnoToError() } iovToMap(iov, niov, params) return int(ret), nil } func Attach(jid int) error { ret := C.jail_attach(C.int(jid)) if ret == -1 { return errnoToError() } return nil } func Remove(jid int) error { ret := C.jail_remove(C.int(jid)) if ret == -1 { return errnoToError() } return nil }