From 3ecd3c8e3d6643986960d6266d71643df8f7c22e Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Fri, 18 Sep 2015 17:45:34 -0400 Subject: Massive documentation and copyright clean-up. --- .gitignore | 1 + LICENSE.txt | 19 + Makefile | 35 +- src/dl/dl_gnu.go | 91 +++-- src/dl/dlfcn.go | 62 +++- src/dl/dlsym_reserved.go | 63 ++++ src/getgr/getgr.go | 18 + src/inotify/bits.go | 67 ++-- src/inotify/inotify.go | 47 ++- src/inotify/inutil/inotify_util.go | 32 +- src/inotify/syscall.go | 42 ++- src/nshd/hackers_git/check_password.go | 21 ++ src/nshd/hackers_git/db_config.go | 28 +- src/nshd/hackers_git/db_group.go | 34 +- src/nshd/hackers_git/db_pam.go | 32 +- src/nshd/hackers_git/db_passwd.go | 32 +- src/nshd/hackers_git/db_shadow.go | 30 +- src/nshd/hackers_git/gid.go | 21 ++ src/nshd/hackers_git/hackers.go | 33 +- src/nshd/hackers_git/hackers_parse.go | 21 ++ src/nshd/hackers_git/hackers_watch.go | 21 ++ src/nshd/hackers_git/set.go | 21 ++ src/nshd/main.go | 24 +- src/nslcd/proto/.gitignore | 4 + src/nslcd/proto/Makefile | 56 +++ src/nslcd/proto/doc.go | 22 ++ src/nslcd/proto/io.go | 172 +++++++++ src/nslcd/proto/nslcd_h.go | 454 ++++++++++++++++++++++++ src/nslcd/proto/server/doc.go | 23 ++ src/nslcd/proto/server/func_handlerequest.go.sh | 101 ++++++ src/nslcd/proto/server/interface_backend.go.sh | 39 ++ src/nslcd/proto/server/type_nilbackend.go.sh | 40 +++ src/nslcd/systemd/disable_nss_module.go | 60 ++++ src/nslcd/systemd/nslcd_systemd.go | 165 +++++++++ src/nslcd_proto/.gitignore | 5 - src/nslcd_proto/Makefile | 36 -- src/nslcd_proto/func_handlerequest.go.sh | 62 ---- src/nslcd_proto/interface_backend.go.sh | 15 - src/nslcd_proto/io.go | 144 -------- src/nslcd_proto/nslcd_h.go | 452 ----------------------- src/nslcd_proto/util.go | 57 --- src/nslcd_proto/util/struct_null_backend.go.sh | 14 - src/nslcd_systemd/disable_nss_module.go | 43 --- src/nslcd_systemd/nslcd_systemd.go | 133 ------- src/sd_daemon/doc.go | 16 + src/sd_daemon/listen_fds.go | 12 +- src/sd_daemon/logger/logger.go | 32 +- src/sd_daemon/lsb/exit-status.go | 41 ++- src/sd_daemon/notify.go | 23 +- test/runner.c | 17 + 50 files changed, 1921 insertions(+), 1112 deletions(-) create mode 100644 LICENSE.txt create mode 100644 src/dl/dlsym_reserved.go create mode 100644 src/nslcd/proto/.gitignore create mode 100644 src/nslcd/proto/Makefile create mode 100644 src/nslcd/proto/doc.go create mode 100644 src/nslcd/proto/io.go create mode 100644 src/nslcd/proto/nslcd_h.go create mode 100644 src/nslcd/proto/server/doc.go create mode 100755 src/nslcd/proto/server/func_handlerequest.go.sh create mode 100755 src/nslcd/proto/server/interface_backend.go.sh create mode 100755 src/nslcd/proto/server/type_nilbackend.go.sh create mode 100644 src/nslcd/systemd/disable_nss_module.go create mode 100644 src/nslcd/systemd/nslcd_systemd.go delete mode 100644 src/nslcd_proto/.gitignore delete mode 100644 src/nslcd_proto/Makefile delete mode 100755 src/nslcd_proto/func_handlerequest.go.sh delete mode 100755 src/nslcd_proto/interface_backend.go.sh delete mode 100644 src/nslcd_proto/io.go delete mode 100644 src/nslcd_proto/nslcd_h.go delete mode 100644 src/nslcd_proto/util.go delete mode 100755 src/nslcd_proto/util/struct_null_backend.go.sh delete mode 100644 src/nslcd_systemd/disable_nss_module.go delete mode 100644 src/nslcd_systemd/nslcd_systemd.go create mode 100644 src/sd_daemon/doc.go diff --git a/.gitignore b/.gitignore index 061fe12..712823c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ /nshd.socket /.Makefile.var.* /.tmp.Makefile.var.* +/LICENSE.*.txt *.o diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..cc96954 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,19 @@ +The software in this repository is under a number of licenses: + + src/getgr LGPL v2.1+ + src/inotify LGPL v2.1+ + src/nslcd LGPL v2.1+ + src/dl GPL v2+, with documentation output clarification + src/nshd GPL v2+ + src/sd_daemon Apache v2.0 + test/ LGPL v2.1+ + +The general notion is that the core application is GPL, while +supporting libraries that might be useful outside of this specific +application are LGPL, with the 2 exceptions: + - The sd_daemon package is Apache licensed because of code taken from + CoreOS and Docker. + - The dl package is GPLv2+ licensed because of wording in comments + taken from the Linux Programmer's Manual. + +For more details, see each individual file. diff --git a/Makefile b/Makefile index 031a775..997f8e8 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,24 @@ +# Copyright 2015 Luke Shumaker . +# +# This is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# The GNU General Public License's references to "object code" and +# "executables" are to be interpreted to also include the output of +# any document formatting or typesetting system, including +# intermediate and printed output. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this manual; if not, see +# . + MAKEFLAGS += --no-builtin-rules prefix = /usr/local bindir = $(prefix)/bin @@ -23,7 +44,7 @@ GOPATH := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) vp = .Makefile.var.% deps = gopkg.in/yaml.v2 -subdirs = src/nslcd_proto +subdirs = src/nslcd/proto all: build @@ -31,7 +52,7 @@ include $(addsuffix /Makefile,$(subdirs)) secondary += test/*.o download += $(addprefix src/,$(deps)) -generate += +generate += LICENSE.lgpl-2.1.txt LICENSE.gpl-2.txt LICENSE.apache-2.0.txt build += bin/nshd nshd.service nshd.socket test/runner install += $(addprefix $(DESTDIR),$(bindir)/nshd $(systemddir)/system/nshd.socket $(systemddir)/system/nshd.service) @@ -51,8 +72,15 @@ uninstall: rmdir -p -- $(sort $(dir $(install))) 2>/dev/null || true .PHONY: uninstall + +LICENSE.lgpl-2.1.txt: $(NET) + curl https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt > $@ +LICENSE.gpl-2.txt: $(NET) + curl https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt > $@ +LICENSE.apache-2.0.txt: $(NET) + curl https://www.apache.org/licenses/LICENSE-2.0 > $@ + $(foreach d,$(deps),$(eval src/$d: $(NET); GOPATH='$(GOPATH)' go get -d -u $d)) -.PHONY: NET bin/nshd: $(download) $(generate) $(gosrc) $(addprefix .Makefile.var.,$(cgo_variables)) @true $(foreach f,$(filter $(vp),$^), && test $@ -nt $f ) || rm -rf -- bin pkg @@ -81,3 +109,4 @@ $(DESTDIR)$(systemddir)/system/%.service: %.service .SECONDARY: .DELETE_ON_ERROR: +.PHONY: NET diff --git a/src/dl/dl_gnu.go b/src/dl/dl_gnu.go index c7c409b..99ec32c 100644 --- a/src/dl/dl_gnu.go +++ b/src/dl/dl_gnu.go @@ -1,44 +1,69 @@ -package dl +// The code in this file is trivial, and not eligable for copyright. +// +// The documentation in this file is taken from the Linux Programmer's +// Manual page for dlopen(3). +// +// Copyright 1995 Yggdrasil Computing, Incorporated. +// written by Adam J. Richter (adam@yggdrasil.com), +// with typesetting help from Daniel Quinlan (quinlan@yggdrasil.com). +// and Copyright 2003, 2015 Michael Kerrisk (mtk.manpages@gmail.com). +// +// This is free documentation; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" +// and "executables" are to be interpreted as the output of any +// document formatting or typesetting system, including +// intermediate and printed output. +// +// This manual is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . +// +// Modified by David A. Wheeler 2000-11-28. +// Applied patch by Terran Melconian, aeb, 2001-12-14. +// Modified by Hacksaw 2003-03-13. +// Modified by Matt Domsch, 2003-04-09: _init and _fini obsolete +// Modified by Michael Kerrisk 2003-05-16. +// Modified by Walter Harms: dladdr, dlvsym +// Modified by Petr Baudis , 2008-12-04: dladdr caveat -import "unsafe" +package dl //#define _GNU_SOURCE -//#include -//#include //#include -//const uintptr_t rtld_next = (uintptr_t)RTLD_NEXT; -//const uintptr_t rtld_default = (uintptr_t)RTLD_DEFAULT; import "C" +// These flags to Open() are GNU libc extensions. const ( - RTLD_NOLOAD Flag = C.RTLD_NOLOAD - RTLD_NODELETE Flag = C.RTLD_NODELETE - RTLD_DEEPBIND Flag = C.RTLD_DEEPBIND -) + // Do not unload the shared object during Close(). + // Consequently, the object's static variables are not + // reinitialized if the object is reloaded with Open() at a + // later time. + RTLD_NODELETE Flag = C.RTLD_NODELETE // (since glibc 2.2, also present on Solaris) -// These are kinda weird in that they aren't required by the standard, -// but they are reserved by the standard (see the documentation for -// `dlsym(3)`). On glibc, it takes _GNU_SOURCE to get them. -// -// There are two special pseudo-handles that may be specified -// in handle: -var ( - RTLD_DEFAULT Handle = Handle{unsafe.Pointer(uintptr(C.rtld_default))} - // Find the first occurrence of the desired symbol using - // the default shared object search order. The search will - // include global symbols in the executable and its - // dependencies, as well as symbols in shared objects that - // were dynamically loaded with the RTLD_GLOBAL flag. - RTLD_NEXT Handle = Handle{unsafe.Pointer(uintptr(C.rtld_next))} - // Find the next occurrence of the desired symbol in the - // search order after the current object. This allows one - // to provide a wrapper around a function in another shared - // object, so that, for example, the definition of a - // function in a preloaded shared object (see LD_PRELOAD in - // ld.so(8)) can find and invoke the "real" function - // provided in another shared object (or for that matter, - // the "next" definition of the function in cases where - // there are multiple layers of preloading). + // Don't load the shared object. This can be used to test if + // the object is already resident (Open() returns nil if it + // is not, or the object's handle if it is resident). This + // flag can also be used to promote the flags on a shared + // object that is already loaded. For example, a shared + // object that was previously loaded with RTLD_LOCAL can be + // reopened with RTLD_NOLOAD | RTLD_GLOBAL. + RTLD_NOLOAD Flag = C.RTLD_NOLOAD // (since glibc 2.2, also present on Solaris) + + // Place the lookup scope of the symbols in this shared object + // ahead of the global scope. This means that a + // self-contained object will use its own symbols in + // preference to global symbols with the same name contained + // in objects that have already been loaded. + RTLD_DEEPBIND Flag = C.RTLD_DEEPBIND // (since glibc 2.3.4) ) // TODO: dlmopen diff --git a/src/dl/dlfcn.go b/src/dl/dlfcn.go index d5467f3..3ab5abb 100644 --- a/src/dl/dlfcn.go +++ b/src/dl/dlfcn.go @@ -1,3 +1,25 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + +// Package dl provides an interface to the POSIX runtime linker. package dl import ( @@ -12,26 +34,39 @@ import "C" type Flag int +// POSIX specifies these four flags to Open(). const ( - RTLD_LAZY Flag = C.RTLD_LAZY // Relocations are performed at an - // implementation-defined time. - RTLD_NOW Flag = C.RTLD_NOW // Relocations are performed when the - // object is loaded. - RTLD_GLOBAL Flag = C.RTLD_GLOBAL // All symbols are available for - // relocation processing of other - // modules. - RTLD_LOCAL Flag = C.RTLD_LOCAL // All symbols are not made available - // for relocation processing by other - // modules. + // Relocations are performed at an implementation-defined + // time. + RTLD_LAZY Flag = C.RTLD_LAZY + + // Relocations are performed when the object is loaded. + RTLD_NOW Flag = C.RTLD_NOW + + // All symbols are available for relocation processing of + // other modules. + RTLD_GLOBAL Flag = C.RTLD_GLOBAL + + // All symbols are not made available for relocation + // processing by other modules. + RTLD_LOCAL Flag = C.RTLD_LOCAL ) type Handle struct { c unsafe.Pointer } +// Open a shared object file, returning a Handle to it, or an error. +// If name is an empty string, then the returned handle is the global +// symbol table for the current process; if the name contains a slash, +// then it is interpretted as a pathname; otherwise, it is +// interpretted in an implementation-defined manner. func Open(name string, flags Flag) (Handle, error) { nameC := C.CString(name) defer C.free(unsafe.Pointer(nameC)) + if name == "" { + nameC = nil + } dlerror() ptr := C.dlopen(nameC, C.int(flags)) @@ -41,8 +76,10 @@ func Open(name string, flags Flag) (Handle, error) { return Handle{ptr}, nil } +// Look up a symbol, and return a pointer to it. +// // This returns uintptr instead of unsafe.Pointer so that code using -// reflect cannot obtain unsafe.Pointers without importing the unsafe +// dl cannot obtain unsafe.Pointers without importing the unsafe // package explicitly. func (h Handle) Sym(symbol string) (uintptr, error) { symbolC := C.CString(symbol) @@ -56,6 +93,9 @@ func (h Handle) Sym(symbol string) (uintptr, error) { return uintptr(ptr), nil } +// Close this handle on a shared object; decrementint the reference +// count; if the reference count drops below 0, then the object is +// unloaded. func (h Handle) Close() error { dlerror() r := C.dlclose(h.c) diff --git a/src/dl/dlsym_reserved.go b/src/dl/dlsym_reserved.go new file mode 100644 index 0000000..081e012 --- /dev/null +++ b/src/dl/dlsym_reserved.go @@ -0,0 +1,63 @@ +// The documentation for RTLD_DEFAULT and RTLD_NEXT is taken from the +// Linux Programmer's Manual page for dlsym(3). +// +// Copyright 1995 Yggdrasil Computing, Incorporated. +// Copyright 2003, 2015 Michael Kerrisk . +// Copyright 2015 Luke Shumaker . +// +// This is free documentation; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" +// and "executables" are to be interpreted as the output of any +// document formatting or typesetting system, including +// intermediate and printed output. +// +// This manual is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + +package dl + +import "unsafe" + +//#define _GNU_SOURCE +//#include +//#include +//const uintptr_t rtld_next = (uintptr_t)RTLD_NEXT; +//const uintptr_t rtld_default = (uintptr_t)RTLD_DEFAULT; +import "C" + +// These constant values for Handles are reserved by POSIX for future +// use with these meanings. They are available in GNU libdl if +// _GNU_SOURCE is defined. +var ( + // This Handle represents the default default shared object + // search order. The search will include global symbols in + // the executable and its dependencies, as well as symbols in + // shared objects that were dynamically loaded with the + // RTLD_GLOBAL flag. + RTLD_DEFAULT Handle + + // This Handle represents the shared object search order after + // the current object. This allows one to provide a wrapper + // around a function in another shared object, so that, for + // example, the definition of a function in a preloaded shared + // object (see LD_PRELOAD in ld.so(8)) can find and invoke the + // "real" function provided in another shared object (or for + // that matter, the "next" definition of the function in cases + // where there are multiple layers of preloading). + RTLD_NEXT Handle +) + +func init() { + RTLD_DEFAULT = Handle{c: unsafe.Pointer(uintptr(C.rtld_default)), o: 2} + RTLD_DEFAULT = Handle{c: unsafe.Pointer(uintptr(C.rtld_next)), o: 2} +} diff --git a/src/getgr/getgr.go b/src/getgr/getgr.go index 5470b2c..5e32826 100644 --- a/src/getgr/getgr.go +++ b/src/getgr/getgr.go @@ -1,3 +1,21 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this manual; if not, see +// . + +// Package getgr provides an interface to query the POSIX group +// database. package getgr import ( diff --git a/src/inotify/bits.go b/src/inotify/bits.go index eb0270f..18d8566 100644 --- a/src/inotify/bits.go +++ b/src/inotify/bits.go @@ -1,3 +1,24 @@ +// Copyright (C) 2015 Luke Shumaker +// +// Many of the comments in this file are taken from the GNU libc +// header file +// +// Copyright (C) 2005-2015 Free Software Foundation, Inc. +// +// The GNU C Library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// The GNU C Library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with the GNU C Library; if not, see +// . + package inotify const ( @@ -7,39 +28,39 @@ const ( IN_NONBLOCK int = 00004000 ) -type Fd int -type Wd int +type file int // File Descriptor +type Wd int // Watch Descriptor type Mask uint32 const ( // Supported events suitable for the `mask` parameter of Inotify.AddWatch(). - IN_ACCESS Mask = (1<< 0) // File was accessed. - IN_MODIFY Mask = (1<< 1) // File was modified. - IN_ATTRIB Mask = (1<< 2) // Metadata changed. - IN_CLOSE_WRITE Mask = (1<< 3) // Writtable file was closed. - IN_CLOSE_NOWRITE Mask = (1<< 4) // Unwrittable file closed. - IN_OPEN Mask = (1<< 5) // File was opened. - IN_MOVED_FROM Mask = (1<< 6) // File was moved from X. - IN_MOVED_TO Mask = (1<< 7) // File was moved to Y. - IN_CREATE Mask = (1<< 8) // Subfile was created. - IN_DELETE Mask = (1<< 9) // Subfile was deleted. - IN_DELETE_SELF Mask = (1<<10) // Self was deleted. - IN_MOVE_SELF Mask = (1<<11) // Self was moved. + IN_ACCESS Mask = (1 << 0) // File was accessed. + IN_MODIFY Mask = (1 << 1) // File was modified. + IN_ATTRIB Mask = (1 << 2) // Metadata changed. + IN_CLOSE_WRITE Mask = (1 << 3) // Writtable file was closed. + IN_CLOSE_NOWRITE Mask = (1 << 4) // Unwrittable file closed. + IN_OPEN Mask = (1 << 5) // File was opened. + IN_MOVED_FROM Mask = (1 << 6) // File was moved from X. + IN_MOVED_TO Mask = (1 << 7) // File was moved to Y. + IN_CREATE Mask = (1 << 8) // Subfile was created. + IN_DELETE Mask = (1 << 9) // Subfile was deleted. + IN_DELETE_SELF Mask = (1 << 10) // Self was deleted. + IN_MOVE_SELF Mask = (1 << 11) // Self was moved. // Events that appear in output without subscribing to them. - IN_UNMOUNT Mask = (1<<13) // Backing fs was unmounted. - IN_Q_OVERFLOW Mask = (1<<14) // Event queued overflowed. - IN_IGNORED Mask = (1<<15) // File was ignored (expect no more events). + IN_UNMOUNT Mask = (1 << 13) // Backing fs was unmounted. + IN_Q_OVERFLOW Mask = (1 << 14) // Event queued overflowed. + IN_IGNORED Mask = (1 << 15) // File was ignored (expect no more events). // Special flags that you may pass to Inotify.AddWatch()... // except for IN_ISDIR, which is a flag that is set on output events. - IN_ONLYDIR Mask = (1<<24) // Only watch the path if it is a directory. - IN_DONT_FOLLOW Mask = (1<<25) // Do not follow a sym link. - IN_EXCL_UNLINK Mask = (1<<26) // Exclude events on unlinked objects. - IN_MASK_ADD Mask = (1<<29) // Add to the mask of an already existing watch. - IN_ISDIR Mask = (1<<30) // Event occurred against dir. - IN_ONESHOT Mask = (1<<31) // Only send event once. + IN_ONLYDIR Mask = (1 << 24) // Only watch the path if it is a directory. + IN_DONT_FOLLOW Mask = (1 << 25) // Do not follow a sym link. + IN_EXCL_UNLINK Mask = (1 << 26) // Exclude events on unlinked objects. + IN_MASK_ADD Mask = (1 << 29) // Add to the mask of an already existing watch. + IN_ISDIR Mask = (1 << 30) // Event occurred against dir. + IN_ONESHOT Mask = (1 << 31) // Only send event once. // Convenience macros */ IN_CLOSE Mask = (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) // Close. diff --git a/src/inotify/inotify.go b/src/inotify/inotify.go index 0d67b44..2fd3a83 100644 --- a/src/inotify/inotify.go +++ b/src/inotify/inotify.go @@ -1,3 +1,21 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this manual; if not, see +// . + +// Package inotify provides an interface to the Linux inotify system. +// The inotify system is a mechanism for monitoring filesystem events. package inotify import ( @@ -7,7 +25,7 @@ import ( ) type Inotify struct { - fd Fd + fd file fdLock sync.RWMutex buffFull [4096]byte buff []byte @@ -15,12 +33,14 @@ type Inotify struct { } type Event struct { - Wd Wd /* Watch descriptor */ - Mask Mask /* Mask describing event */ - Cookie uint32 /* Unique cookie associating related events (for rename(2)) */ - Name *string /* Optional name */ + Wd Wd // Watch descriptor + Mask Mask // Mask describing event + Cookie uint32 // Unique cookie associating related events (for rename(2)) + Name *string // Optional name } +// Create an inotify instance. The variant InotifyInit1() allows +// flags to access extra functionality. func InotifyInit() (*Inotify, error) { fd, err := inotify_init() o := Inotify{ @@ -30,6 +50,8 @@ func InotifyInit() (*Inotify, error) { return &o, err } +// Create an inotify instance, with flags specifying extra +// functionality. func InotifyInit1(flags int) (*Inotify, error) { fd, err := inotify_init1(flags) o := Inotify{ @@ -39,18 +61,29 @@ func InotifyInit1(flags int) (*Inotify, error) { return &o, err } +// Add a watch to the inotify instance, or modifies an existing watch +// item. func (o *Inotify) AddWatch(path string, mask Mask) (Wd, error) { o.fdLock.RLock() defer o.fdLock.RUnlock() return inotify_add_watch(o.fd, path, mask) } +// Remove a watch from the inotify instance. func (o *Inotify) RmWatch(wd Wd) error { o.fdLock.RLock() defer o.fdLock.RUnlock() return inotify_rm_watch(o.fd, wd) } +// Close the inotify instance; further calls to this object will +// error. +// +// Events recieved before Close() is called may still be Read() after +// the call to Close(). +// +// Beware that if Close() is called while waiting on Read(), it will +// block until events are read. func (o *Inotify) Close() error { o.fdLock.Lock() defer o.fdLock.Unlock() @@ -58,6 +91,10 @@ func (o *Inotify) Close() error { return sysclose(o.fd) } +// Read an event from the inotify instance. +// +// Events recieved before Close() is called may still be Read() after +// the call to Close(). func (o *Inotify) Read() (Event, error) { o.buffLock.Lock() defer o.buffLock.Unlock() diff --git a/src/inotify/inutil/inotify_util.go b/src/inotify/inutil/inotify_util.go index 3a5eed5..c643e59 100644 --- a/src/inotify/inutil/inotify_util.go +++ b/src/inotify/inutil/inotify_util.go @@ -1,3 +1,20 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this manual; if not, see +// . + +// Package inutil provides a channel-based interface to inotify. package inutil import ( @@ -6,25 +23,21 @@ import ( "syscall" ) -const ( - // Flags for the parameter of InotifyInit1(). - // These, oddly, appear to be 24-bit numbers. - IN_CLOEXEC = inotify.IN_CLOEXEC -) - type Watcher struct { Events <-chan inotify.Event - events chan<- inotify.Event Errors <-chan error + events chan<- inotify.Event errors chan<- error in *inotify.Inotify } +// Wraps inotify.InotifyInit() func WatcherInit() (*Watcher, error) { in, err := inotify.InotifyInit() return newWatcher(in, err) } +// Wraps inotify.InotifyInit1() func WatcherInit1(flags int) (*Watcher, error) { in, err := inotify.InotifyInit1(flags &^ inotify.IN_NONBLOCK) return newWatcher(in, err) @@ -44,14 +57,19 @@ func newWatcher(in *inotify.Inotify, err error) (*Watcher, error) { return o, err } +// Wraps inotify.Inotify.AddWatch(); adds or modifies a watch. func (o *Watcher) AddWatch(path string, mask inotify.Mask) (inotify.Wd, error) { return o.in.AddWatch(path, mask) } +// Wraps inotify.Inotify.RmWatch(); removes a watch. func (o *Watcher) RmWatch(wd inotify.Wd) error { return o.in.RmWatch(wd) } +// Wraps inotify.Inotify.Close(). Unlike inotify.Inotify.Close(), +// this cannot block. Also unlike inotify.Inotify.Close(), nothing +// may be received from the channel after this is called. func (o *Watcher) Close() { func() { defer recover() diff --git a/src/inotify/syscall.go b/src/inotify/syscall.go index 721a10a..d1b5140 100644 --- a/src/inotify/syscall.go +++ b/src/inotify/syscall.go @@ -1,3 +1,19 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this manual; if not, see +// . + package inotify import ( @@ -12,27 +28,27 @@ func newPathError(op string, path string, err error) error { return &os.PathError{Op: op, Path: path, Err: err} } -/* Create and initialize inotify instance. */ -func inotify_init() (Fd, error) { +// Create and initialize inotify instance. +func inotify_init() (file, error) { fd, errno := syscall.InotifyInit() - return Fd(fd), os.NewSyscallError("inotify_init", errno) + return file(fd), os.NewSyscallError("inotify_init", errno) } -/* Create and initialize inotify instance. */ -func inotify_init1(flags int) (Fd, error) { +// Create and initialize inotify instance. +func inotify_init1(flags int) (file, error) { fd, errno := syscall.InotifyInit1(flags) - return Fd(fd), os.NewSyscallError("inotify_init1", errno) + return file(fd), os.NewSyscallError("inotify_init1", errno) } -/* Add watch of object NAME to inotify instance FD. Notify about - events specified by MASK. */ -func inotify_add_watch(fd Fd, name string, mask Mask) (Wd, error) { +// Add watch of object NAME to inotify instance FD. Notify about +// events specified by MASK. +func inotify_add_watch(fd file, name string, mask Mask) (Wd, error) { wd, errno := syscall.InotifyAddWatch(int(fd), name, uint32(mask)) return Wd(wd), newPathError("inotify_add_watch", name, errno) } -/* Remove the watch specified by WD from the inotify instance FD. */ -func inotify_rm_watch(fd Fd, wd Wd) error { +// Remove the watch specified by WD from the inotify instance FD. +func inotify_rm_watch(fd file, wd Wd) error { success, errno := syscall.InotifyRmWatch(int(fd), uint32(wd)) switch success { case -1: @@ -49,11 +65,11 @@ func inotify_rm_watch(fd Fd, wd Wd) error { panic("should never happen") } -func sysclose(fd Fd) error { +func sysclose(fd file) error { return os.NewSyscallError("close", syscall.Close(int(fd))) } -func sysread(fd Fd, p []byte) (int, error) { +func sysread(fd file, p []byte) (int, error) { n, err := syscall.Read(int(fd), p) return n, os.NewSyscallError("read", err) } diff --git a/src/nshd/hackers_git/check_password.go b/src/nshd/hackers_git/check_password.go index c112641..81ad932 100644 --- a/src/nshd/hackers_git/check_password.go +++ b/src/nshd/hackers_git/check_password.go @@ -1,3 +1,24 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git import "unsafe" diff --git a/src/nshd/hackers_git/db_config.go b/src/nshd/hackers_git/db_config.go index 7e96059..ffacf00 100644 --- a/src/nshd/hackers_git/db_config.go +++ b/src/nshd/hackers_git/db_config.go @@ -1,8 +1,32 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git -import p "nslcd_proto" +import ( + p "nslcd/proto" + s "syscall" +) -func (o *Hackers) Config_Get(cred p.Ucred, req p.Request_Config_Get) <-chan p.Config { +func (o *Hackers) Config_Get(cred s.Ucred, req p.Request_Config_Get) <-chan p.Config { o.lock.RLock() ret := make(chan p.Config) go func() { diff --git a/src/nshd/hackers_git/db_group.go b/src/nshd/hackers_git/db_group.go index 3122bd2..4f27627 100644 --- a/src/nshd/hackers_git/db_group.go +++ b/src/nshd/hackers_git/db_group.go @@ -1,6 +1,30 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git -import p "nslcd_proto" +import ( + p "nslcd/proto" + s "syscall" +) func (o *Hackers) groupByName(name string, users bool) p.Group { members_set, found := o.groups[name] @@ -48,7 +72,7 @@ func (o *Hackers) groupByGid(gid int32, users bool) p.Group { } } -func (o *Hackers) Group_ByName(cred p.Ucred, req p.Request_Group_ByName) <-chan p.Group { +func (o *Hackers) Group_ByName(cred s.Ucred, req p.Request_Group_ByName) <-chan p.Group { o.lock.RLock() ret := make(chan p.Group) go func() { @@ -64,7 +88,7 @@ func (o *Hackers) Group_ByName(cred p.Ucred, req p.Request_Group_ByName) <-chan return ret } -func (o *Hackers) Group_ByGid(cred p.Ucred, req p.Request_Group_ByGid) <-chan p.Group { +func (o *Hackers) Group_ByGid(cred s.Ucred, req p.Request_Group_ByGid) <-chan p.Group { o.lock.RLock() ret := make(chan p.Group) go func() { @@ -81,7 +105,7 @@ func (o *Hackers) Group_ByGid(cred p.Ucred, req p.Request_Group_ByGid) <-chan p. } // note that the BYMEMBER call returns an empty members list -func (o *Hackers) Group_ByMember(cred p.Ucred, req p.Request_Group_ByMember) <-chan p.Group { +func (o *Hackers) Group_ByMember(cred s.Ucred, req p.Request_Group_ByMember) <-chan p.Group { o.lock.RLock() ret := make(chan p.Group) go func() { @@ -102,7 +126,7 @@ func (o *Hackers) Group_ByMember(cred p.Ucred, req p.Request_Group_ByMember) <-c return ret } -func (o *Hackers) Group_All(cred p.Ucred, req p.Request_Group_All) <-chan p.Group { +func (o *Hackers) Group_All(cred s.Ucred, req p.Request_Group_All) <-chan p.Group { o.lock.RLock() ret := make(chan p.Group) go func() { diff --git a/src/nshd/hackers_git/db_pam.go b/src/nshd/hackers_git/db_pam.go index 126c403..230e111 100644 --- a/src/nshd/hackers_git/db_pam.go +++ b/src/nshd/hackers_git/db_pam.go @@ -1,12 +1,34 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git import ( "crypto/rand" "math/big" - p "nslcd_proto" + p "nslcd/proto" + s "syscall" ) -func (o *Hackers) PAM_Authentication(cred p.Ucred, req p.Request_PAM_Authentication) <-chan p.PAM_Authentication { +func (o *Hackers) PAM_Authentication(cred s.Ucred, req p.Request_PAM_Authentication) <-chan p.PAM_Authentication { o.lock.RLock() ret := make(chan p.PAM_Authentication) go func() { @@ -35,7 +57,7 @@ func (o *Hackers) PAM_Authentication(cred p.Ucred, req p.Request_PAM_Authenticat return ret } -func (o *Hackers) PAM_Authorization(cred p.Ucred, req p.Request_PAM_Authorization) <-chan p.PAM_Authorization { +func (o *Hackers) PAM_Authorization(cred s.Ucred, req p.Request_PAM_Authorization) <-chan p.PAM_Authorization { o.lock.RLock() ret := make(chan p.PAM_Authorization) go func() { @@ -58,7 +80,7 @@ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 var alphabet_len = big.NewInt(int64(len(alphabet))) -func (o *Hackers) PAM_SessionOpen(cred p.Ucred, req p.Request_PAM_SessionOpen) <-chan p.PAM_SessionOpen { +func (o *Hackers) PAM_SessionOpen(cred s.Ucred, req p.Request_PAM_SessionOpen) <-chan p.PAM_SessionOpen { ret := make(chan p.PAM_SessionOpen) go func() { defer close(ret) @@ -76,7 +98,7 @@ func (o *Hackers) PAM_SessionOpen(cred p.Ucred, req p.Request_PAM_SessionOpen) < return ret } -func (o *Hackers) PAM_SessionClose(cred p.Ucred, req p.Request_PAM_SessionClose) <-chan p.PAM_SessionClose { +func (o *Hackers) PAM_SessionClose(cred s.Ucred, req p.Request_PAM_SessionClose) <-chan p.PAM_SessionClose { ret := make(chan p.PAM_SessionClose) go close(ret) return ret diff --git a/src/nshd/hackers_git/db_passwd.go b/src/nshd/hackers_git/db_passwd.go index cc8c711..1283ec1 100644 --- a/src/nshd/hackers_git/db_passwd.go +++ b/src/nshd/hackers_git/db_passwd.go @@ -1,6 +1,30 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git -import p "nslcd_proto" +import ( + p "nslcd/proto" + s "syscall" +) /* Note that the output password hash value should be one of: - no password set, allow login without password @@ -9,7 +33,7 @@ import p "nslcd_proto" often used to indicate that the password is defined elsewhere other - encrypted password, in crypt(3) format */ -func (o *Hackers) Passwd_ByName(cred p.Ucred, req p.Request_Passwd_ByName) <-chan p.Passwd { +func (o *Hackers) Passwd_ByName(cred s.Ucred, req p.Request_Passwd_ByName) <-chan p.Passwd { o.lock.RLock() ret := make(chan p.Passwd) go func() { @@ -27,7 +51,7 @@ func (o *Hackers) Passwd_ByName(cred p.Ucred, req p.Request_Passwd_ByName) <-cha return ret } -func (o *Hackers) Passwd_ByUID(cred p.Ucred, req p.Request_Passwd_ByUID) <-chan p.Passwd { +func (o *Hackers) Passwd_ByUID(cred s.Ucred, req p.Request_Passwd_ByUID) <-chan p.Passwd { o.lock.RLock() ret := make(chan p.Passwd) go func() { @@ -45,7 +69,7 @@ func (o *Hackers) Passwd_ByUID(cred p.Ucred, req p.Request_Passwd_ByUID) <-chan return ret } -func (o *Hackers) Passwd_All(cred p.Ucred, req p.Request_Passwd_All) <-chan p.Passwd { +func (o *Hackers) Passwd_All(cred s.Ucred, req p.Request_Passwd_All) <-chan p.Passwd { o.lock.RLock() ret := make(chan p.Passwd) go func() { diff --git a/src/nshd/hackers_git/db_shadow.go b/src/nshd/hackers_git/db_shadow.go index 594e7a1..c83f223 100644 --- a/src/nshd/hackers_git/db_shadow.go +++ b/src/nshd/hackers_git/db_shadow.go @@ -1,8 +1,32 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git -import p "nslcd_proto" +import ( + p "nslcd/proto" + s "syscall" +) -func (o *Hackers) Shadow_ByName(cred p.Ucred, req p.Request_Shadow_ByName) <-chan p.Shadow { +func (o *Hackers) Shadow_ByName(cred s.Ucred, req p.Request_Shadow_ByName) <-chan p.Shadow { o.lock.RLock() ret := make(chan p.Shadow) go func() { @@ -29,7 +53,7 @@ func (o *Hackers) Shadow_ByName(cred p.Ucred, req p.Request_Shadow_ByName) <-cha return ret } -func (o *Hackers) Shadow_All(cred p.Ucred, req p.Request_Shadow_All) <-chan p.Shadow { +func (o *Hackers) Shadow_All(cred s.Ucred, req p.Request_Shadow_All) <-chan p.Shadow { o.lock.RLock() ret := make(chan p.Shadow) go func() { diff --git a/src/nshd/hackers_git/gid.go b/src/nshd/hackers_git/gid.go index ee8c10d..d8293d7 100644 --- a/src/nshd/hackers_git/gid.go +++ b/src/nshd/hackers_git/gid.go @@ -1,3 +1,24 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git import "getgr" diff --git a/src/nshd/hackers_git/hackers.go b/src/nshd/hackers_git/hackers.go index 1eca0f6..5b57a63 100644 --- a/src/nshd/hackers_git/hackers.go +++ b/src/nshd/hackers_git/hackers.go @@ -1,11 +1,34 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + +// Package hackers_git is an nslcd_server Backend that speaks to +// hackers.git. package hackers_git import ( "inotify" "inotify/inutil" - "nslcd_proto" - "nslcd_proto/util" - "nslcd_systemd" + "nslcd/proto" + "nslcd/proto/server" + "nslcd/systemd" "sd_daemon/logger" "sync" ) @@ -21,7 +44,7 @@ type Config struct { } type Hackers struct { - util.NullBackend + nslcd_server.NilBackend Cfg Config lock sync.RWMutex workers sync.WaitGroup @@ -37,7 +60,7 @@ type Hackers struct { } var _ nslcd_systemd.Backend = &Hackers{} -var _ nslcd_proto.Backend = &Hackers{} +var _ nslcd_server.Backend = &Hackers{} func (o *Hackers) Init() error { err := o.Reload() diff --git a/src/nshd/hackers_git/hackers_parse.go b/src/nshd/hackers_git/hackers_parse.go index 46c878e..63e5c0f 100644 --- a/src/nshd/hackers_git/hackers_parse.go +++ b/src/nshd/hackers_git/hackers_parse.go @@ -1,3 +1,24 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git import ( diff --git a/src/nshd/hackers_git/hackers_watch.go b/src/nshd/hackers_git/hackers_watch.go index 8559f88..d2c5bce 100644 --- a/src/nshd/hackers_git/hackers_watch.go +++ b/src/nshd/hackers_git/hackers_watch.go @@ -1,3 +1,24 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git import ( diff --git a/src/nshd/hackers_git/set.go b/src/nshd/hackers_git/set.go index 9faf0f4..dc1d443 100644 --- a/src/nshd/hackers_git/set.go +++ b/src/nshd/hackers_git/set.go @@ -1,3 +1,24 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + package hackers_git func set2list(set map[string]bool) []string { diff --git a/src/nshd/main.go b/src/nshd/main.go index 775aca2..d9c1277 100644 --- a/src/nshd/main.go +++ b/src/nshd/main.go @@ -1,8 +1,30 @@ +// Copyright 2015 Luke Shumaker . +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// The GNU General Public License's references to "object code" and +// "executables" are to be interpreted to also include the output of +// any document formatting or typesetting system, including +// intermediate and printed output. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// . + +// Command nshd is an implementation of nslcd that talks to hackers.git instead of LDAP. package main import ( "nshd/hackers_git" - "nslcd_systemd" + "nslcd/systemd" "os" ) diff --git a/src/nslcd/proto/.gitignore b/src/nslcd/proto/.gitignore new file mode 100644 index 0000000..b3f9749 --- /dev/null +++ b/src/nslcd/proto/.gitignore @@ -0,0 +1,4 @@ +/requests.txt +/server/func_handlerequest.go +/server/interface_backend.go +/server/type_nilbackend.go diff --git a/src/nslcd/proto/Makefile b/src/nslcd/proto/Makefile new file mode 100644 index 0000000..2335374 --- /dev/null +++ b/src/nslcd/proto/Makefile @@ -0,0 +1,56 @@ +# Copyright (C) 2015 Luke Shumaker +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +d := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + +generate += $d/server/interface_backend.go +generate += $d/server/func_handlerequest.go +generate += $d/server/type_nilbackend.go +secondary += $d/requests.txt + +ifeq (1,$(words $(MAKEFILE_LIST))) + +all: generate +.PHONY: all + +generate: $(generate) +.PHONY: generate + +clean: + rm -f -- $(generate) $(secondary) +.PHONY: clean + +.DELETE_ON_ERROR: +.SECONDARY: + +else + +# fix these to the current value of `d` +generate := $(generate) +secondary := $(secondary) + +endif + +$d/requests.txt: $d/nslcd_h.go $d/Makefile + < $< grep -Eo '\btype Request_([^_ ]+)(_\S+)?' | sed 's/^type Request_//' > $@ + +%.go: %.go.sh + ./$^ > $@ + +$d/server/interface_backend.go: $d/requests.txt +$d/server/func_handlerequest.go: $d/requests.txt +$d/server/type_nilbackend.go: $d/server/interface_backend.go diff --git a/src/nslcd/proto/doc.go b/src/nslcd/proto/doc.go new file mode 100644 index 0000000..70929f3 --- /dev/null +++ b/src/nslcd/proto/doc.go @@ -0,0 +1,22 @@ +// Copyright (C) 2015 Luke Shumaker +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +// Package nslcd_proto implements the nslcd protocol of nss-pam-ldapd. +// +// The godoc documentation for this packages isn't very good; you +// should look at the source file nslcd_h.go. +package nslcd_proto diff --git a/src/nslcd/proto/io.go b/src/nslcd/proto/io.go new file mode 100644 index 0000000..3c0c5be --- /dev/null +++ b/src/nslcd/proto/io.go @@ -0,0 +1,172 @@ +// Copyright (C) 2015 Luke Shumaker +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +package nslcd_proto + +import ( + "encoding/binary" + "fmt" + "io" + "net" + "reflect" + "syscall" +) + +type NslcdError string + +func (o NslcdError) Error() string { + return string(o) +} + +type nslcdObject interface { + nslcdWrite(fd io.Writer) +} + +type nslcdObjectPtr interface { + nslcdRead(fd io.Reader) +} + +// Write an object to a stream. In the event of an error, this +// function may panic! Handle it! +func Write(fd io.Writer, data interface{}) { + switch data := data.(type) { + // basic data types + case nslcdObject: + data.nslcdWrite(fd) + case []byte: + _, err := fd.Write(data) + if err != nil { + panic(err) + } + case int32: + err := binary.Write(fd, binary.BigEndian, data) + if err != nil { + panic(err) + } + // composite datatypes + case string: + Write(fd, int32(len(data))) + Write(fd, []byte(data)) + case []string: + Write(fd, int32(len(data))) + for _, item := range data { + Write(fd, item) + } + case net.IP: + var af int32 = -1 + switch len(data) { + case net.IPv4len: + af = syscall.AF_INET + case net.IPv6len: + af = syscall.AF_INET6 + } + var bytes []byte + if af < 0 { + bytes = make([]byte, 0) + } else { + bytes = data + } + Write(fd, af) + Write(fd, int32(len(bytes))) + Write(fd, bytes) + case []net.IP: + Write(fd, int32(len(data))) + for _, item := range data { + Write(fd, item) + } + default: + v := reflect.ValueOf(data) + switch v.Kind() { + case reflect.Struct: + for i, n := 0, v.NumField(); i < n; i++ { + Write(fd, v.Field(i).Interface()) + } + default: + panic(fmt.Sprintf("Invalid structure to write NSLCD protocol data from: %T ( %#v )", data, data)) + } + } +} + +// Read an object from a stream. In the event of an error, this +// function may panic! Handle it! +func Read(fd io.Reader, data interface{}) { + switch data := data.(type) { + // basic data types + case nslcdObjectPtr: + data.nslcdRead(fd) + case *[]byte: + _, err := fd.Read(*data) + if err != nil { + panic(err) + } + case *int32: + err := binary.Read(fd, binary.BigEndian, data) + if err != nil { + panic(err) + } + // composite datatypes + case *string: + var len int32 + Read(fd, &len) + buf := make([]byte, len) + Read(fd, &buf) + *data = string(buf) + case *[]string: + var num int32 + Read(fd, &num) + *data = make([]string, num) + for i := 0; i < int(num); i++ { + Read(fd, &((*data)[i])) + } + case *net.IP: + var af int32 + Read(fd, &af) + var _len int32 + switch af { + case syscall.AF_INET: + _len = net.IPv4len + case syscall.AF_INET6: + _len = net.IPv6len + default: + panic(NslcdError(fmt.Sprintf("incorrect address family specified: %d", af))) + } + var len int32 + Read(fd, &len) + if len != _len { + panic(NslcdError(fmt.Sprintf("address length incorrect: %d", len))) + } + buf := make([]byte, len) + Read(fd, &buf) + *data = buf + case *[]net.IP: + var num int32 + Read(fd, &num) + *data = make([]net.IP, num) + for i := 0; i < int(num); i++ { + Read(fd, &((*data)[i])) + } + default: + p := reflect.ValueOf(data) + v := reflect.Indirect(p) + if p == v || v.Kind() != reflect.Struct { + panic(fmt.Sprintf("The argument to nslcd_proto/internal.Read() must be a pointer: %T ( %#v )", data, data)) + } + for i, n := 0, v.NumField(); i < n; i++ { + Read(fd, v.Field(i).Addr().Interface()) + } + } +} diff --git a/src/nslcd/proto/nslcd_h.go b/src/nslcd/proto/nslcd_h.go new file mode 100644 index 0000000..cb210cd --- /dev/null +++ b/src/nslcd/proto/nslcd_h.go @@ -0,0 +1,454 @@ +// This file is based heavily on nslcd.h from nss-pam-ldapd +// Copyright (C) 2015 Luke Shumaker +/* + nslcd.h - file describing client/server protocol + + Copyright (C) 2006 West Consulting + Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012, 2013 Arthur de Jong + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +package nslcd_proto + +import ( + "fmt" + "io" + "net" +) + +/* + The protocol used between the nslcd client and server is a simple binary + protocol. It is request/response based where the client initiates a + connection, does a single request and closes the connection again. Any + mangled or not understood messages will be silently ignored by the server. + + A request looks like: + INT32 NSLCD_VERSION + INT32 NSLCD_ACTION_* + [request parameters if any] + A response looks like: + INT32 NSLCD_VERSION + INT32 NSLCD_ACTION_* (the original request type) + [result(s)] + INT32 NSLCD_RESULT_END + A single result entry looks like: + NSLCD_RESULT_BEGIN int32 + [result value(s)] + If a response would return multiple values (e.g. for NSLCD_ACTION_*_ALL + functions) each return value will be preceded by a NSLCD_RESULT_BEGIN + value. After the last returned result the server sends + NSLCD_RESULT_END. If some error occurs (e.g. LDAP server unavailable, + error in the request, etc) the server terminates the connection to signal + an error condition (breaking the protocol). + + These are the available basic data types: + INT32 - 32-bit integer value + TYPE - a typed field that is transferred using sizeof() + STRING - a string length (32bit) followed by the string value (not + null-terminted) the string itself is assumed to be UTF-8 + STRINGLIST - a 32-bit number noting the number of strings followed by + the strings one at a time + + Furthermore the ADDRESS compound data type is defined as: + INT32 type of address: e.g. AF_INET or AF_INET6 + INT32 lenght of address + RAW the address itself + With the ADDRESSLIST using the same construct as with STRINGLIST. + + The protocol uses network byte order for all types. +*/ +// These basic data types are implemented in `io.go` + +/* The current version of the protocol. This protocol should only be + updated with major backwards-incompatible changes. */ +const NSLCD_VERSION int32 = 0x00000002 + +/* Get a NSLCD configuration option. There is one request parameter: */ +type Request_Config_Get struct { + Key int32 /* NSLCD_CONFIG_* */ +} +/* the result value is: */ +type Config struct { + Value string /* interpretation depending on request */ +} +const NSLCD_ACTION_CONFIG_GET int32 = 0x00010001 + +const ( + /* return the message, if any, that is presented to the user when password + modification through PAM is prohibited */ + NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE int32 = 1 +) + +/* Email alias (/etc/aliases) NSS requests. The result values for a + single entry are: */ +type Alias struct { + Name string + Recipients []string +} +const NSLCD_ACTION_ALIAS_BYNAME int32 = 0x00020001; type Request_Alias_ByName struct { Name string } +const NSLCD_ACTION_ALIAS_ALL int32 = 0x00020008; type Request_Alias_All struct {} + +/* Ethernet address/name mapping NSS requests. The result values for a + single entry are: */ +type Ether struct { + Name string + Address [6]byte +} +const NSLCD_ACTION_ETHER_BYNAME int32 = 0x00030001; type Request_Ether_ByName struct { Name string } +const NSLCD_ACTION_ETHER_BYETHER int32 = 0x00030002; type Request_Ether_ByEther struct { Ether [6]byte } +const NSLCD_ACTION_ETHER_ALL int32 = 0x00030008; type Request_Ether_All struct {} + +/* Group and group membership related NSS requests. The result values + for a single entry are: */ +type Group struct { + Name string + PwHash string + ID int32 + Members []string +} +/* (note that the BYMEMER call returns an emtpy members list) */ +const NSLCD_ACTION_GROUP_BYNAME int32 = 0x00040001; type Request_Group_ByName struct { Name string } +const NSLCD_ACTION_GROUP_BYGID int32 = 0x00040002; type Request_Group_ByGid struct { Gid int32 } +const NSLCD_ACTION_GROUP_BYMEMBER int32 = 0x00040006; type Request_Group_ByMember struct { Member string } +const NSLCD_ACTION_GROUP_ALL int32 = 0x00040008; type Request_Group_All struct {} + +/* Hostname (/etc/hosts) lookup NSS requests. The result values + for an entry are: */ +type Host struct { + Name string + Aliases []string + Addresses []net.IP +} +const NSLCD_ACTION_HOST_BYNAME int32 = 0x00050001; type Request_Host_ByName struct { Name string } +const NSLCD_ACTION_HOST_BYADDR int32 = 0x00050002; type Request_Host_ByAddr struct { Addr net.IP } +const NSLCD_ACTION_HOST_ALL int32 = 0x00050008; type Request_Host_All struct {} + +/* Netgroup NSS result entries contain a number of parts. A result entry + starts with: + STRING netgroup name + followed by zero or more references to other netgroups or netgroup + triples. A reference to another netgroup looks like: + INT32 NSLCD_NETGROUP_TYPE_NETGROUP + STRING other netgroup name + A a netgroup triple looks like: + INT32 NSLCD_NETGROUP_TYPE_TRIPLE + STRING host + STRING user + STRING domain + A netgroup result entry is terminated by: + INT32 NSLCD_NETGROUP_TYPE_END + */ +type Netgroup_Netgroup struct { + Name string +} +type Netgroup_Triple struct { + Host string + User string + Domain string +} +type Netgroup_PartList []interface{} +func (data Netgroup_PartList) nslcdWrite(fd io.Writer) { + for _, part := range data { + var t int32 = -1 + switch part.(type) { + case Netgroup_Netgroup: + t = NSLCD_NETGROUP_TYPE_NETGROUP + case Netgroup_Triple: + t = NSLCD_NETGROUP_TYPE_TRIPLE + } + if t < 0 { + panic("unrecognized netgroup type") + } + Write(fd, t) + Write(fd, part) + } + Write(fd, NSLCD_NETGROUP_TYPE_END) +} +func (data *Netgroup_PartList) nslcdRead(fd io.Reader) { + *data = make([]interface{}, 0) + for { + var t int32 + var v interface{} + Read(fd, &t) + switch t { + case NSLCD_NETGROUP_TYPE_NETGROUP: + v = Netgroup_Netgroup{} + case NSLCD_NETGROUP_TYPE_TRIPLE: + v = Netgroup_Triple{} + case NSLCD_NETGROUP_TYPE_END: + return + default: + panic(NslcdError(fmt.Sprintf("unrecognized netgroup type: %#08x", t))) + } + Read(fd, &v) + *data = append(*data, v) + } +} +var _ nslcdObject = Netgroup_PartList{} +var _ nslcdObjectPtr = &Netgroup_PartList{} +type Netgroup struct { + Name string + Parts Netgroup_PartList +} +const NSLCD_ACTION_NETGROUP_BYNAME int32 = 0x00060001; type Request_Netgroup_ByName struct { Name string } +const NSLCD_ACTION_NETGROUP_ALL int32 = 0x00060008; type Request_Netgroup_All struct {} +const ( + NSLCD_NETGROUP_TYPE_NETGROUP int32 = 1 + NSLCD_NETGROUP_TYPE_TRIPLE int32 = 2 + NSLCD_NETGROUP_TYPE_END int32 = 3 +) + +/* Network name (/etc/networks) NSS requests. Result values for a single + entry are: */ +type Network struct { + Name string + Aliases []string + Addresses []net.IP +} +const NSLCD_ACTION_NETWORK_BYNAME int32 = 0x00070001; type Request_Network_ByName struct { Name string } +const NSLCD_ACTION_NETWORK_BYADDR int32 = 0x00070002; type Request_Network_ByAddr struct { Addr net.IP } +const NSLCD_ACTION_NETWORK_ALL int32 = 0x00070008; type Request_Network_All struct {} + +/* User account (/etc/passwd) NSS requests. Result values are: */ +type Passwd struct { + Name string + PwHash string + UID int32 + GID int32 + GECOS string + HomeDir string + Shell string +} +const NSLCD_ACTION_PASSWD_BYNAME int32 = 0x00080001; type Request_Passwd_ByName struct { Name string } +const NSLCD_ACTION_PASSWD_BYUID int32 = 0x00080002; type Request_Passwd_ByUID struct { UID int32 } +const NSLCD_ACTION_PASSWD_ALL int32 = 0x00080008; type Request_Passwd_All struct {} + +/* Protocol information requests. Result values are: */ +type Protocol struct { + Name string + Aliases []string + Number int32 +} +const NSLCD_ACTION_PROTOCOL_BYNAME int32 = 0x00090001; type Request_Protocol_ByName struct { Name string } +const NSLCD_ACTION_PROTOCOL_BYNUMBER int32 = 0x00090002; type Request_Protocol_ByNumber struct { Number int32 } +const NSLCD_ACTION_PROTOCOL_ALL int32 = 0x00090008; type Request_Protocol_All struct {} + +/* RPC information requests. Result values are: */ +type RPC struct { + Name string + Aliases []string + Number int32 +} +const NSLCD_ACTION_RPC_BYNAME int32 = 0x000a0001; type Request_RPC_ByName struct { Name string } +const NSLCD_ACTION_RPC_BYNUMBER int32 = 0x000a0002; type Request_RPC_ByNumber struct { Number int32 } +const NSLCD_ACTION_RPC_ALL int32 = 0x000a0008; type Request_RPC_All struct {} + +/* Service (/etc/services) information requests. The BYNAME and BYNUMBER + requests contain an extra protocol string in the request which, if not + blank, will filter the services by this protocol. Result values are: */ +type Service struct { + Name string + Aliases []string + PortNumber int32 + Protocol string +} +const NSLCD_ACTION_SERVICE_BYNAME int32 = 0x000b0001; type Request_Service_ByName struct { Name string } +const NSLCD_ACTION_SERVICE_BYNUMBER int32 = 0x000b0002; type Request_Service_ByNumber struct { Number int32 } +const NSLCD_ACTION_SERVICE_ALL int32 = 0x000b0008; type Request_Service_All struct {} + +/* Extended user account (/etc/shadow) information requests. Result + values for a single entry are: */ +type Shadow struct { + // It is my understanding that an empty value for an INT32 + // field is expressed with a negative number. -- lukeshu + Name string + PwHash string + LastChangeDate int32 + MinDays int32 + MaxDays int32 + WarnDays int32 + InactDays int32 + ExpireDate int32 + Flag int32 +} +const NSLCD_ACTION_SHADOW_BYNAME int32 = 0x000c0001; type Request_Shadow_ByName struct { Name string } +const NSLCD_ACTION_SHADOW_ALL int32 = 0x000c0008; type Request_Shadow_All struct {} + +/* PAM-related requests. The request parameters for all these requests + begin with: */ +type PAM_Base struct { + UserName string + ServiceName string + RUser string + RHost string + TTY string +} +/* If the user is not known in LDAP no result may be returned (immediately + return NSLCD_RESULT_END instead of a PAM error code). */ + +/* PAM authentication check request. The extra request values are: */ +type Request_PAM_Authentication struct { + PAM_Base + Password string +} +/* and the result value consists of: */ +type PAM_Authentication struct { + AuthenticationResult int32 + UserName string + AuthorizationResult int32 + AuthorizationError string +} +/* If the username is empty in this request an attempt is made to + authenticate as the administrator (set using rootpwmoddn). + Some authorisation checks are already done during authentication so the + response also includes authorisation information. */ +const NSLCD_ACTION_PAM_AUTHENTICATION int32 = 0x000d0001 + +/* PAM authorisation check request. The result value consists of: */ +type PAM_Authorization struct { + Result int32 + Error string +} +/* The authentication check may have already returned some authorisation + information. The authorisation error message, if supplied, will be used + by the PAM module instead of a message that is generated by the PAM + module itself. */ +const NSLCD_ACTION_PAM_AUTHORIZATION int32 = 0x000d0002; type Request_PAM_Authorization PAM_Base + +/* PAM session open request. The result value consists of: */ +type PAM_SessionOpen struct { + SessionID string +} +/* This session id may be used to close this session with. */ +const NSLCD_ACTION_PAM_SESSIONOPEN int32 = 0x000d0003; type Request_PAM_SessionOpen PAM_Base + +/* PAM session close request. This request has the following + extra request value: */ +type Request_PAM_SessionClose struct { + PAM_Base + SessionID string +} +/* and this calls only returns an empty response value. */ +type PAM_SessionClose struct {} +const NSLCD_ACTION_PAM_SESSIONCLOSE int32 = 0x000d0004 + +/* PAM password modification request. This requests has the following extra + request values: */ +type Request_PAM_PwMod struct { + PAM_Base + AsRoot int32 /* 0=oldpasswd is user passwd, 1=oldpasswd is root passwd */ + OldPassword string + NewPassword string +} +/* and returns the result values: */ +type PAM_PwMod struct { + Result int32 + Error string +} +const NSLCD_ACTION_PAM_PWMOD int32 = 0x000d0005 + +/* User information change request. This request allows one to change + their full name and other information. The request parameters for this + request are: + STRING user name + INT32 asroot: 0=passwd is user passwd, 1=passwd is root passwd + STRING password + followed by one or more of the below, terminated by NSLCD_USERMOD_END + INT32 NSLCD_USERMOD_* + STRING new value + the response consists of one or more of the entries below, terminated + by NSLCD_USERMOD_END: + INT32 NSLCD_USERMOD_* + STRING response + (if the response is blank, the change went OK, otherwise the string + contains an error message) + */ +type UserMod_Item struct { + Key int32 + Value string +} +type UserMod_ItemList []UserMod_Item +func (data UserMod_ItemList) nslcdWrite(fd io.Writer) { + for _, item := range data { + Write(fd, item) + } + Write(fd, NSLCD_USERMOD_END) +} +func (data *UserMod_ItemList) nslcdRead(fd io.Reader) { + *data = make([]UserMod_Item, 0) + for { + var t int32 + Read(fd, &t) + if t == NSLCD_USERMOD_END { + return + } + var v UserMod_Item + Read(fd, &v) + *data = append(*data, v) + } +} +var _ nslcdObject = UserMod_ItemList{} +var _ nslcdObjectPtr = &UserMod_ItemList{} +type Request_UserMod struct { + UserName string + AsRoot int32 + Password string + Items UserMod_ItemList +} +type UserMod struct { + Items []UserMod_Item +} +const NSLCD_ACTION_USERMOD int32 = 0x000e0001 + +/* These are the possible values for the NSLCD_ACTION_USERMOD operation + above. */ +const ( + NSLCD_USERMOD_END int32 = 0 /* end of change values */ + NSLCD_USERMOD_RESULT int32 = 1 /* global result value */ + NSLCD_USERMOD_FULLNAME int32 = 2 /* full name */ + NSLCD_USERMOD_ROOMNUMBER int32 = 3 /* room number */ + NSLCD_USERMOD_WORKPHONE int32 = 4 /* office phone number */ + NSLCD_USERMOD_HOMEPHONE int32 = 5 /* home phone number */ + NSLCD_USERMOD_OTHER int32 = 6 /* other info */ + NSLCD_USERMOD_HOMEDIR int32 = 7 /* home directory */ + NSLCD_USERMOD_SHELL int32 = 8 /* login shell */ +) + +/* Request result codes. */ +const ( + NSLCD_RESULT_BEGIN int32 = 1 + NSLCD_RESULT_END int32 = 2 +) + +/* Partial list of PAM result codes. */ +const ( + NSLCD_PAM_SUCCESS int32 = 0 /* everything ok */ + NSLCD_PAM_PERM_DENIED int32 = 6 /* Permission denied */ + NSLCD_PAM_AUTH_ERR int32 = 7 /* Authc failure */ + NSLCD_PAM_CRED_INSUFFICIENT int32 = 8 /* Cannot access authc data */ + NSLCD_PAM_AUTHINFO_UNAVAIL int32 = 9 /* Cannot retrieve authc info */ + NSLCD_PAM_USER_UNKNOWN int32 = 10 /* User not known */ + NSLCD_PAM_MAXTRIES int32 = 11 /* Retry limit reached */ + NSLCD_PAM_NEW_AUTHTOK_REQD int32 = 12 /* Password expired */ + NSLCD_PAM_ACCT_EXPIRED int32 = 13 /* Account expired */ + NSLCD_PAM_SESSION_ERR int32 = 14 /* Cannot make/remove session record */ + NSLCD_PAM_AUTHTOK_ERR int32 = 20 /* Authentication token manipulation error */ + NSLCD_PAM_AUTHTOK_DISABLE_AGING int32 = 23 /* Password aging disabled */ + NSLCD_PAM_IGNORE int32 = 25 /* Ignore module */ + NSLCD_PAM_ABORT int32 = 26 /* Fatal error */ + NSLCD_PAM_AUTHTOK_EXPIRED int32 = 27 /* authentication token has expired */ +) diff --git a/src/nslcd/proto/server/doc.go b/src/nslcd/proto/server/doc.go new file mode 100644 index 0000000..72ae2fe --- /dev/null +++ b/src/nslcd/proto/server/doc.go @@ -0,0 +1,23 @@ +// Copyright (C) 2015 Luke Shumaker +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +// Package nslcd_server is a framework for implementing an nslcd +// server. +// +// You write an implementation of the Backend interface, then pass +// that to the HandleRequest function for each connection. +package nslcd_server diff --git a/src/nslcd/proto/server/func_handlerequest.go.sh b/src/nslcd/proto/server/func_handlerequest.go.sh new file mode 100755 index 0000000..3ef2758 --- /dev/null +++ b/src/nslcd/proto/server/func_handlerequest.go.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +# -*- Mode: Go -*- +# Copyright (C) 2015 Luke Shumaker +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +requests=$1 +printf '//' +printf ' %q' "$0" "$@" +printf '\n// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n' +cat < +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +requests=$1 +printf '//' +printf ' %q' "$0" "$@" +printf '\n// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n' +cat < +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +interface=$1 +printf '//' +printf ' %q' "$0" "$@" +printf '\n// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n' +cat < +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +package nslcd_systemd + +import ( + "dl" + "sd_daemon/logger" + "unsafe" +) + +//static char *strary(char **ary, unsigned int n) { return ary[n]; } +import "C" + +const ( + nss_module_soname = "libnss_ldap.so.2" + nss_module_sym_version = "_nss_ldap_version" + nss_module_sym_enablelookups = "_nss_ldap_enablelookups" +) + +func disable_nss_module() { + handle, err := dl.Open(nss_module_soname, dl.RTLD_LAZY|dl.RTLD_NODELETE) + if err == nil { + defer handle.Close() + } else { + logger.Warning("NSS module %s not loaded: %v", nss_module_soname, err) + return + } + + c_version_info, err := handle.Sym(nss_module_sym_version) + if err == nil { + g_version_info := (**C.char)(unsafe.Pointer(c_version_info)) + logger.Debug("NSS module %s version %s %s", nss_module_soname, + C.GoString(C.strary(g_version_info, 0)), + C.GoString(C.strary(g_version_info, 1))) + } else { + logger.Warning("NSS module %s version missing: %v", nss_module_soname, err) + } + c_enable_flag, err := handle.Sym(nss_module_sym_enablelookups) + if err != nil { + logger.Warning("Unable to disable NSS ldap module for nslcd process: %v", err) + return + } + g_enable_flag := (*C.int)(unsafe.Pointer(c_enable_flag)) + *g_enable_flag = 0 +} diff --git a/src/nslcd/systemd/nslcd_systemd.go b/src/nslcd/systemd/nslcd_systemd.go new file mode 100644 index 0000000..f5d4881 --- /dev/null +++ b/src/nslcd/systemd/nslcd_systemd.go @@ -0,0 +1,165 @@ +// Copyright (C) 2015 Luke Shumaker +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +// Package nslcd_systemd does the legwork for implementing a systemd +// socket-activated nslcd server. +// +// You just need to implement the Backend interface, then pass it to +// Main, which will return the exit code for the process. Everything +// but the backend is taken care of for you! +// +// package main +// +// import "nslcd/systemd" +// +// func main() { +// backend := ... +// os.Exit(int(nslcd_systemd.Main(backend))) +// } +package nslcd_systemd + +import ( + "fmt" + "net" + "nslcd/proto/server" + "os" + "os/signal" + sd "sd_daemon" + "sd_daemon/logger" + "sd_daemon/lsb" + "sync" + "syscall" +) + +type Backend interface { + nslcd_server.Backend + Init() error + Reload() error + Close() +} + +func get_socket() (socket net.Listener, err error) { + socket = nil + err = nil + fds := sd.ListenFds(true) + if fds == nil { + err = fmt.Errorf("Failed to aquire sockets from systemd") + return + } + if len(fds) != 1 { + err = fmt.Errorf("Wrong number of sockets from systemd: expected %d but got %d", 1, len(fds)) + return + } + socket, err = net.FileListener(fds[0]) + fds[0].Close() + return +} + +func getpeercred(conn *net.UnixConn) (cred syscall.Ucred, err error) { + file, err := conn.File() + if err != nil { + return + } + defer file.Close() + _cred, err := syscall.GetsockoptUcred(int(file.Fd()), syscall.SOL_SOCKET, syscall.SO_PEERCRED) + cred = *_cred + return +} + +func handler(conn *net.UnixConn, backend nslcd_server.Backend) { + defer conn.Close() + cred, err := getpeercred(conn) + if err != nil { + logger.Debug("Connection from unknown client") + } else { + logger.Debug("Connection from pid=%v uid=%v gid=%v", + cred.Pid, cred.Uid, cred.Gid) + } + err = nslcd_server.HandleRequest(backend, conn, conn, cred) + if err != nil { + logger.Notice("Error while handling request: %v", err) + } +} + +func Main(backend Backend) uint8 { + var err error = nil + + sigs := make(chan os.Signal) + signal.Notify(sigs, syscall.SIGTERM, syscall.SIGHUP) + + disable_nss_module() + + err = backend.Init() + if err != nil { + logger.Err("Could not initialize backend: %v", err) + sd.Notify(false, "STOPPING=1") + return lsb.EXIT_FAILURE + } + defer backend.Close() + + socket, err := get_socket() + if err != nil { + logger.Err("%v", err) + sd.Notify(false, "STOPPING=1") + return lsb.EXIT_NOTRUNNING + } + defer socket.Close() + sock := make(chan *net.UnixConn) + go func() { + defer lsb.Recover() + for { + conn, err := socket.Accept() + if err != nil { + logger.Notice("%v", err) + } + if conn != nil { + sock <- conn.(*net.UnixConn) + } + } + }() + + var wg sync.WaitGroup + defer wg.Wait() + defer sd.Notify(false, "STOPPING=1") + sd.Notify(false, "READY=1") + for { + select { + case sig := <-sigs: + switch sig { + case syscall.SIGTERM: + logger.Notice("Received SIGTERM, shutting down") + return lsb.EXIT_SUCCESS + case syscall.SIGHUP: + sd.Notify(false, "RELOADING=1") + err := backend.Reload() + if err != nil { + logger.Notice("Could not reload backend: %s", err.Error()) + return lsb.EXIT_NOTRUNNING + } + sd.Notify(false, "READY=1") + } + case conn := <-sock: + wg.Add(1) + go func() { + defer lsb.Recover() + defer wg.Done() + handler(conn, backend) + }() + } + } + panic("not reached") +} diff --git a/src/nslcd_proto/.gitignore b/src/nslcd_proto/.gitignore deleted file mode 100644 index 0915898..0000000 --- a/src/nslcd_proto/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/interface_backend.go -/util/struct_null_backend.go -/func_handlerequest.go -/requests.txt -/responses.txt diff --git a/src/nslcd_proto/Makefile b/src/nslcd_proto/Makefile deleted file mode 100644 index 9e3ba4e..0000000 --- a/src/nslcd_proto/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -_ := $(MAKEFILE_LIST) -d := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) - -generate := $(generate) $d/interface_backend.go $d/func_handlerequest.go $d/util/struct_null_backend.go -secondary := $d/requests.txt - -ifeq (,$(filter clean,$(MAKECMDGOALS))) --include $d/enumerator-list.mk -endif - -ifeq (1,$(words $_)) - -all: generate -.PHONY: all - -generate: $(generate) -.PHONY: generate - -clean: - rm -f -- $(generate) $(secondary) -.PHONY: clean - -.DELETE_ON_ERROR: -.SECONDARY: - -endif - -$d/requests.txt: $d/nslcd_h.go $d/Makefile - < $< grep -Eo '\btype Request_([^_ ]+)(_\S+)?' | sed 's/^type Request_//' > $@ - -%.go: %.go.sh - ./$^ > $@ - -$d/interface_backend.go: $d/requests.txt -$d/func_handlerequest.go: $d/requests.txt -$d/util/struct_null_backend.go: $d/interface_backend.go diff --git a/src/nslcd_proto/func_handlerequest.go.sh b/src/nslcd_proto/func_handlerequest.go.sh deleted file mode 100755 index 4b89a8a..0000000 --- a/src/nslcd_proto/func_handlerequest.go.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash -# -*- Mode: Go -*- -requests=$1 -cat < import "C" +// Returns a list of file descriptors passed in by the service manager +// as part of the socket-based activation logic. +// +// If unsetEnv is true, then (regarless of whether the function call +// itself succeeds or not) it will unset the environmental variables +// LISTEN_FDS and LISTEN_PID, which will cause further calls to this +// function to fail. +// +// In the case of an error, this function returns nil. func ListenFds(unsetEnv bool) []*os.File { if unsetEnv { defer os.Unsetenv("LISTEN_PID") diff --git a/src/sd_daemon/logger/logger.go b/src/sd_daemon/logger/logger.go index f8f3bd6..850df1c 100644 --- a/src/sd_daemon/logger/logger.go +++ b/src/sd_daemon/logger/logger.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package logger implements a simple stderr-based logger with systemd +// log levels. package logger import ( @@ -23,15 +25,23 @@ import ( import "C" func log(level string, format string, a ...interface{}) { - f := level + format + "\n" - fmt.Fprintf(os.Stderr, f, a...) + f := level + format + "\n" + fmt.Fprintf(os.Stderr, f, a...) } - -/* system is unusable */ func Emerg( format string, a ...interface{}) { log(C.SD_EMERG , format, a...); } -/* action must be taken immediately */ func Alert( format string, a ...interface{}) { log(C.SD_ALERT , format, a...); } -/* critical conditions */ func Crit( format string, a ...interface{}) { log(C.SD_CRIT , format, a...); } -/* error conditions */ func Err( format string, a ...interface{}) { log(C.SD_ERR , format, a...); } -/* warning conditions */ func Warning(format string, a ...interface{}) { log(C.SD_WARNING, format, a...); } -/* normal but significant condition */ func Notice( format string, a ...interface{}) { log(C.SD_NOTICE , format, a...); } -/* informational */ func Info( format string, a ...interface{}) { log(C.SD_INFO , format, a...); } -/* debug-level messages */ func Debug( format string, a ...interface{}) { log(C.SD_DEBUG , format, a...); } + +// system is unusable +func Emerg( format string, a ...interface{}) { log(C.SD_EMERG , format, a...); } +// action must be taken immediately +func Alert( format string, a ...interface{}) { log(C.SD_ALERT , format, a...); } +// critical conditions +func Crit( format string, a ...interface{}) { log(C.SD_CRIT , format, a...); } +// error conditions +func Err( format string, a ...interface{}) { log(C.SD_ERR , format, a...); } +// warning conditions +func Warning(format string, a ...interface{}) { log(C.SD_WARNING, format, a...); } +// normal but significant condition +func Notice( format string, a ...interface{}) { log(C.SD_NOTICE , format, a...); } +// informational +func Info( format string, a ...interface{}) { log(C.SD_INFO , format, a...); } +// debug-level messages +func Debug( format string, a ...interface{}) { log(C.SD_DEBUG , format, a...); } diff --git a/src/sd_daemon/lsb/exit-status.go b/src/sd_daemon/lsb/exit-status.go index 41eaafd..cc1604d 100644 --- a/src/sd_daemon/lsb/exit-status.go +++ b/src/sd_daemon/lsb/exit-status.go @@ -1,3 +1,19 @@ +// Copyright 2015 Luke Shumaker +// +// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package lsb provides constant exit codes specified by the Linux +// Standard Base. package lsb import ( @@ -5,11 +21,10 @@ import ( "sd_daemon/logger" ) -/* systemd daemon(7) recommends using the exit codes defined in the - * "LSB recomendations for SysV init scripts"[1]. - * - * [1]: http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html - */ +// systemd daemon(7) recommends using the exit codes defined in the +// "LSB recomendations for SysV init scripts"[1]. +// +// [1]: http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html const ( EXIT_SUCCESS uint8 = 0 EXIT_FAILURE uint8 = 1 @@ -19,13 +34,13 @@ const ( EXIT_NOTINSTALLED uint8 = 5 EXIT_NOTCONFIGURED uint8 = 6 EXIT_NOTRUNNING uint8 = 7 - /* 8- 99 are reserved for future LSB use */ - /* 100-149 are reserved for distribution use */ - /* 150-199 are reserved for application use */ - /* 200-254 are reserved for init system use */ + // 8- 99 are reserved for future LSB use + // 100-149 are reserved for distribution use + // 150-199 are reserved for application use + // 200-254 are reserved for init system use - /* Therefore, the following are taken from systemd's - /* `src/basic/exit-status.h` */ + // Therefore, the following are taken from systemd's + // `src/basic/exit-status.h` EXIT_CHDIR uint8 = 200 EXIT_NICE uint8 = 201 EXIT_FDS uint8 = 202 @@ -49,7 +64,7 @@ const ( EXIT_SETSID uint8 = 220 EXIT_CONFIRM uint8 = 221 EXIT_STDERR uint8 = 222 - _EXIT_RESERVED uint8 = 223 /* used to be tcpwrap don't reuse! */ + _EXIT_RESERVED uint8 = 223 // used to be tcpwrap don't reuse! EXIT_PAM uint8 = 224 EXIT_NETWORK uint8 = 225 EXIT_NAMESPACE uint8 = 226 @@ -66,6 +81,8 @@ const ( EXIT_SMACK_PROCESS_LABEL uint8 = 237 ) +// This is a utility function to defer at the beginning of a goroutine +// in order to have the correct exit code in the case of a panic. func Recover() { if r := recover(); r != nil { logger.Err("panic: %v", r) diff --git a/src/sd_daemon/notify.go b/src/sd_daemon/notify.go index a038f54..8fce6da 100644 --- a/src/sd_daemon/notify.go +++ b/src/sd_daemon/notify.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package sd_daemon +package sd import ( "errors" @@ -22,11 +22,22 @@ import ( "os" ) -// ErrNotifyNoSocket is an error returned if no socket was specified. -var ErrNotifyNoSocket = errors.New("No socket") +// errNotifyNoSocket is an error returned if no socket was specified. +var errNotifyNoSocket = errors.New("No socket") -// Notify sends a message to the init daemon. It is common to ignore -// the error. +// Notify sends a message to the service manager aobout state +// changes. It is common to ignore the error. +// +// If unsetEnv is true, then (regarless of whether the function call +// itself succeeds or not) it will unset the environmental variable +// NOTIFY_SOCKET, which will cause further calls to this function to +// fail. +// +// The state parameter should countain a newline-separated list of +// variable assignments. +// +// See the documentation for sd_notify(3) for well-known variable +// assignments. func Notify(unsetEnv bool, state string) error { if unsetEnv { defer os.Unsetenv("NOTIFY_SOCKET") @@ -38,7 +49,7 @@ func Notify(unsetEnv bool, state string) error { } if socketAddr.Name == "" { - return ErrNotifyNoSocket + return errNotifyNoSocket } conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr) diff --git a/test/runner.c b/test/runner.c index 9edd191..110819d 100644 --- a/test/runner.c +++ b/test/runner.c @@ -1,3 +1,20 @@ +/* Copyright (C) 2015 Luke Shumaker + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ #define _GNU_SOURCE #include #include -- cgit v1.2.2