Fix unknow driver test error

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 8856c1ec9557e58917421bf1b32724262745a795)
Signed-off-by: selansen <elango.siva@docker.com>
This commit is contained in:
Brian Goff 2018-06-20 17:02:20 -07:00 committed by selansen
parent f04280986e
commit 5525c22635
46 changed files with 13 additions and 9731 deletions

View File

@ -210,7 +210,7 @@ func TestUnknownDriver(t *testing.T) {
t.Fatal("Expected to fail. But instead succeeded")
}
if errdefs.IsNotFound(err) {
if !errdefs.IsNotFound(err) {
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
}
}

View File

@ -14,8 +14,8 @@ github.com/coreos/go-systemd v17
github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
github.com/docker/docker 71cd53e4a197b303c6ba086bd584ffd67a884281
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef

View File

@ -1,51 +0,0 @@
// +build openbsd,cgo
/*
Copyright The containerd Authors.
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 console
import (
"os"
"golang.org/x/sys/unix"
)
//#include <stdlib.h>
import "C"
const (
cmdTcGet = unix.TIOCGETA
cmdTcSet = unix.TIOCSETA
)
// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f *os.File) (string, error) {
ptspath, err := C.ptsname(C.int(f.Fd()))
if err != nil {
return "", err
}
return C.GoString(ptspath), nil
}
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f *os.File) error {
if _, err := C.grantpt(C.int(f.Fd())); err != nil {
return err
}
return nil
}

View File

@ -1,47 +0,0 @@
// +build openbsd,!cgo
/*
Copyright The containerd Authors.
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.
*/
//
// Implementing the functions below requires cgo support. Non-cgo stubs
// versions are defined below to enable cross-compilation of source code
// that depends on these functions, but the resultant cross-compiled
// binaries cannot actually be used. If the stub function(s) below are
// actually invoked they will display an error message and cause the
// calling process to exit.
//
package console
import (
"os"
"golang.org/x/sys/unix"
)
const (
cmdTcGet = unix.TIOCGETA
cmdTcSet = unix.TIOCSETA
)
func ptsname(f *os.File) (string, error) {
panic("ptsname() support requires cgo.")
}
func unlockpt(f *os.File) error {
panic("unlockpt() support requires cgo.")
}

View File

@ -1,5 +0,0 @@
CoreOS Project
Copyright 2018 CoreOS, Inc
This product includes software developed at CoreOS, Inc.
(http://www.coreos.com/).

View File

@ -1,175 +0,0 @@
// Copyright 2016 CoreOS, Inc.
//
// 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.
// +build cgo
package util
// #include <stdlib.h>
// #include <sys/types.h>
// #include <unistd.h>
//
// int
// my_sd_pid_get_owner_uid(void *f, pid_t pid, uid_t *uid)
// {
// int (*sd_pid_get_owner_uid)(pid_t, uid_t *);
//
// sd_pid_get_owner_uid = (int (*)(pid_t, uid_t *))f;
// return sd_pid_get_owner_uid(pid, uid);
// }
//
// int
// my_sd_pid_get_unit(void *f, pid_t pid, char **unit)
// {
// int (*sd_pid_get_unit)(pid_t, char **);
//
// sd_pid_get_unit = (int (*)(pid_t, char **))f;
// return sd_pid_get_unit(pid, unit);
// }
//
// int
// my_sd_pid_get_slice(void *f, pid_t pid, char **slice)
// {
// int (*sd_pid_get_slice)(pid_t, char **);
//
// sd_pid_get_slice = (int (*)(pid_t, char **))f;
// return sd_pid_get_slice(pid, slice);
// }
//
// int
// am_session_leader()
// {
// return (getsid(0) == getpid());
// }
import "C"
import (
"fmt"
"syscall"
"unsafe"
"github.com/coreos/pkg/dlopen"
)
var libsystemdNames = []string{
// systemd < 209
"libsystemd-login.so.0",
"libsystemd-login.so",
// systemd >= 209 merged libsystemd-login into libsystemd proper
"libsystemd.so.0",
"libsystemd.so",
}
func getRunningSlice() (slice string, err error) {
var h *dlopen.LibHandle
h, err = dlopen.GetHandle(libsystemdNames)
if err != nil {
return
}
defer func() {
if err1 := h.Close(); err1 != nil {
err = err1
}
}()
sd_pid_get_slice, err := h.GetSymbolPointer("sd_pid_get_slice")
if err != nil {
return
}
var s string
sl := C.CString(s)
defer C.free(unsafe.Pointer(sl))
ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl)
if ret < 0 {
err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret))
return
}
return C.GoString(sl), nil
}
func runningFromSystemService() (ret bool, err error) {
var h *dlopen.LibHandle
h, err = dlopen.GetHandle(libsystemdNames)
if err != nil {
return
}
defer func() {
if err1 := h.Close(); err1 != nil {
err = err1
}
}()
sd_pid_get_owner_uid, err := h.GetSymbolPointer("sd_pid_get_owner_uid")
if err != nil {
return
}
var uid C.uid_t
errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid)
serrno := syscall.Errno(-errno)
// when we're running from a unit file, sd_pid_get_owner_uid returns
// ENOENT (systemd <220), ENXIO (systemd 220-223), or ENODATA
// (systemd >=234)
switch {
case errno >= 0:
ret = false
case serrno == syscall.ENOENT, serrno == syscall.ENXIO, serrno == syscall.ENODATA:
// Since the implementation of sessions in systemd relies on
// the `pam_systemd` module, using the sd_pid_get_owner_uid
// heuristic alone can result in false positives if that module
// (or PAM itself) is not present or properly configured on the
// system. As such, we also check if we're the session leader,
// which should be the case if we're invoked from a unit file,
// but not if e.g. we're invoked from the command line from a
// user's login session
ret = C.am_session_leader() == 1
default:
err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno))
}
return
}
func currentUnitName() (unit string, err error) {
var h *dlopen.LibHandle
h, err = dlopen.GetHandle(libsystemdNames)
if err != nil {
return
}
defer func() {
if err1 := h.Close(); err1 != nil {
err = err1
}
}()
sd_pid_get_unit, err := h.GetSymbolPointer("sd_pid_get_unit")
if err != nil {
return
}
var s string
u := C.CString(s)
defer C.free(unsafe.Pointer(u))
ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u)
if ret < 0 {
err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret))
return
}
unit = C.GoString(u)
return
}

View File

@ -1,23 +0,0 @@
// Copyright 2016 CoreOS, Inc.
//
// 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.
// +build !cgo
package util
func getRunningSlice() (string, error) { return "", ErrNoCGO }
func runningFromSystemService() (bool, error) { return false, ErrNoCGO }
func currentUnitName() (string, error) { return "", ErrNoCGO }

View File

@ -1,5 +0,0 @@
CoreOS Project
Copyright 2014 CoreOS, Inc
This product includes software developed at CoreOS, Inc.
(http://www.coreos.com/).

View File

@ -1,4 +0,0 @@
a collection of go utility packages
[![Build Status](https://travis-ci.org/coreos/pkg.png?branch=master)](https://travis-ci.org/coreos/pkg)
[![Godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/coreos/pkg)

View File

@ -1,82 +0,0 @@
// Copyright 2016 CoreOS, Inc.
//
// 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 dlopen provides some convenience functions to dlopen a library and
// get its symbols.
package dlopen
// #cgo LDFLAGS: -ldl
// #include <stdlib.h>
// #include <dlfcn.h>
import "C"
import (
"errors"
"fmt"
"unsafe"
)
var ErrSoNotFound = errors.New("unable to open a handle to the library")
// LibHandle represents an open handle to a library (.so)
type LibHandle struct {
Handle unsafe.Pointer
Libname string
}
// GetHandle tries to get a handle to a library (.so), attempting to access it
// by the names specified in libs and returning the first that is successfully
// opened. Callers are responsible for closing the handler. If no library can
// be successfully opened, an error is returned.
func GetHandle(libs []string) (*LibHandle, error) {
for _, name := range libs {
libname := C.CString(name)
defer C.free(unsafe.Pointer(libname))
handle := C.dlopen(libname, C.RTLD_LAZY)
if handle != nil {
h := &LibHandle{
Handle: handle,
Libname: name,
}
return h, nil
}
}
return nil, ErrSoNotFound
}
// GetSymbolPointer takes a symbol name and returns a pointer to the symbol.
func (l *LibHandle) GetSymbolPointer(symbol string) (unsafe.Pointer, error) {
sym := C.CString(symbol)
defer C.free(unsafe.Pointer(sym))
C.dlerror()
p := C.dlsym(l.Handle, sym)
e := C.dlerror()
if e != nil {
return nil, fmt.Errorf("error resolving symbol %q: %v", symbol, errors.New(C.GoString(e)))
}
return p, nil
}
// Close closes a LibHandle.
func (l *LibHandle) Close() error {
C.dlerror()
C.dlclose(l.Handle)
e := C.dlerror()
if e != nil {
return fmt.Errorf("error closing %v: %v", l.Libname, errors.New(C.GoString(e)))
}
return nil
}

View File

@ -1,56 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// 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.
//
// +build linux
package dlopen
// #include <string.h>
// #include <stdlib.h>
//
// int
// my_strlen(void *f, const char *s)
// {
// size_t (*strlen)(const char *);
//
// strlen = (size_t (*)(const char *))f;
// return strlen(s);
// }
import "C"
import (
"fmt"
"unsafe"
)
func strlen(libs []string, s string) (int, error) {
h, err := GetHandle(libs)
if err != nil {
return -1, fmt.Errorf(`couldn't get a handle to the library: %v`, err)
}
defer h.Close()
f := "strlen"
cs := C.CString(s)
defer C.free(unsafe.Pointer(cs))
strlen, err := h.GetSymbolPointer(f)
if err != nil {
return -1, fmt.Errorf(`couldn't get symbol %q: %v`, f, err)
}
len := C.my_strlen(strlen, cs)
return int(len), nil
}

View File

@ -1,65 +0,0 @@
## `filepath-securejoin` ##
[![Build Status](https://travis-ci.org/cyphar/filepath-securejoin.svg?branch=master)](https://travis-ci.org/cyphar/filepath-securejoin)
An implementation of `SecureJoin`, a [candidate for inclusion in the Go
standard library][go#20126]. The purpose of this function is to be a "secure"
alternative to `filepath.Join`, and in particular it provides certain
guarantees that are not provided by `filepath.Join`.
This is the function prototype:
```go
func SecureJoin(root, unsafePath string) (string, error)
```
This library **guarantees** the following:
* If no error is set, the resulting string **must** be a child path of
`SecureJoin` and will not contain any symlink path components (they will all
be expanded).
* When expanding symlinks, all symlink path components **must** be resolved
relative to the provided root. In particular, this can be considered a
userspace implementation of how `chroot(2)` operates on file paths. Note that
these symlinks will **not** be expanded lexically (`filepath.Clean` is not
called on the input before processing).
* Non-existant path components are unaffected by `SecureJoin` (similar to
`filepath.EvalSymlinks`'s semantics).
* The returned path will always be `filepath.Clean`ed and thus not contain any
`..` components.
A (trivial) implementation of this function on GNU/Linux systems could be done
with the following (note that this requires root privileges and is far more
opaque than the implementation in this library, and also requires that
`readlink` is inside the `root` path):
```go
package securejoin
import (
"os/exec"
"path/filepath"
)
func SecureJoin(root, unsafePath string) (string, error) {
unsafePath = string(filepath.Separator) + unsafePath
cmd := exec.Command("chroot", root,
"readlink", "--canonicalize-missing", "--no-newline", unsafePath)
output, err := cmd.CombinedOutput()
if err != nil {
return "", err
}
expanded := string(output)
return filepath.Join(root, expanded), nil
}
```
[go#20126]: https://github.com/golang/go/issues/20126
### License ###
The license of this project is the same as Go, which is a BSD 3-clause license
available in the `LICENSE` file.

View File

@ -1,135 +0,0 @@
// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
// Copyright (C) 2017 SUSE LLC. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package securejoin is an implementation of the hopefully-soon-to-be-included
// SecureJoin helper that is meant to be part of the "path/filepath" package.
// The purpose of this project is to provide a PoC implementation to make the
// SecureJoin proposal (https://github.com/golang/go/issues/20126) more
// tangible.
package securejoin
import (
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
"syscall"
"github.com/pkg/errors"
)
// ErrSymlinkLoop is returned by SecureJoinVFS when too many symlinks have been
// evaluated in attempting to securely join the two given paths.
var ErrSymlinkLoop = fmt.Errorf("SecureJoin: too many links")
// IsNotExist tells you if err is an error that implies that either the path
// accessed does not exist (or path components don't exist). This is
// effectively a more broad version of os.IsNotExist.
func IsNotExist(err error) bool {
// If it's a bone-fide ENOENT just bail.
if os.IsNotExist(errors.Cause(err)) {
return true
}
// Check that it's not actually an ENOTDIR, which in some cases is a more
// convoluted case of ENOENT (usually involving weird paths).
var errno error
switch err := errors.Cause(err).(type) {
case *os.PathError:
errno = err.Err
case *os.LinkError:
errno = err.Err
case *os.SyscallError:
errno = err.Err
}
return errno == syscall.ENOTDIR || errno == syscall.ENOENT
}
// SecureJoinVFS joins the two given path components (similar to Join) except
// that the returned path is guaranteed to be scoped inside the provided root
// path (when evaluated). Any symbolic links in the path are evaluated with the
// given root treated as the root of the filesystem, similar to a chroot. The
// filesystem state is evaluated through the given VFS interface (if nil, the
// standard os.* family of functions are used).
//
// Note that the guarantees provided by this function only apply if the path
// components in the returned string are not modified (in other words are not
// replaced with symlinks on the filesystem) after this function has returned.
// Such a symlink race is necessarily out-of-scope of SecureJoin.
func SecureJoinVFS(root, unsafePath string, vfs VFS) (string, error) {
// Use the os.* VFS implementation if none was specified.
if vfs == nil {
vfs = osVFS{}
}
var path bytes.Buffer
n := 0
for unsafePath != "" {
if n > 255 {
return "", ErrSymlinkLoop
}
// Next path component, p.
i := strings.IndexRune(unsafePath, filepath.Separator)
var p string
if i == -1 {
p, unsafePath = unsafePath, ""
} else {
p, unsafePath = unsafePath[:i], unsafePath[i+1:]
}
// Create a cleaned path, using the lexical semantics of /../a, to
// create a "scoped" path component which can safely be joined to fullP
// for evaluation. At this point, path.String() doesn't contain any
// symlink components.
cleanP := filepath.Clean(string(filepath.Separator) + path.String() + p)
if cleanP == string(filepath.Separator) {
path.Reset()
continue
}
fullP := filepath.Clean(root + cleanP)
// Figure out whether the path is a symlink.
fi, err := vfs.Lstat(fullP)
if err != nil && !IsNotExist(err) {
return "", err
}
// Treat non-existent path components the same as non-symlinks (we
// can't do any better here).
if IsNotExist(err) || fi.Mode()&os.ModeSymlink == 0 {
path.WriteString(p)
path.WriteRune(filepath.Separator)
continue
}
// Only increment when we actually dereference a link.
n++
// It's a symlink, expand it by prepending it to the yet-unparsed path.
dest, err := vfs.Readlink(fullP)
if err != nil {
return "", err
}
// Absolute symlinks reset any work we've already done.
if filepath.IsAbs(dest) {
path.Reset()
}
unsafePath = dest + string(filepath.Separator) + unsafePath
}
// We have to clean path.String() here because it may contain '..'
// components that are entirely lexical, but would be misleading otherwise.
// And finally do a final clean to ensure that root is also lexically
// clean.
fullP := filepath.Clean(string(filepath.Separator) + path.String())
return filepath.Clean(root + fullP), nil
}
// SecureJoin is a wrapper around SecureJoinVFS that just uses the os.* library
// of functions as the VFS. If in doubt, use this function over SecureJoinVFS.
func SecureJoin(root, unsafePath string) (string, error) {
return SecureJoinVFS(root, unsafePath, nil)
}

View File

@ -1 +0,0 @@
github.com/pkg/errors v0.8.0

View File

@ -1,41 +0,0 @@
// Copyright (C) 2017 SUSE LLC. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package securejoin
import "os"
// In future this should be moved into a separate package, because now there
// are several projects (umoci and go-mtree) that are using this sort of
// interface.
// VFS is the minimal interface necessary to use SecureJoinVFS. A nil VFS is
// equivalent to using the standard os.* family of functions. This is mainly
// used for the purposes of mock testing, but also can be used to otherwise use
// SecureJoin with VFS-like system.
type VFS interface {
// Lstat returns a FileInfo describing the named file. If the file is a
// symbolic link, the returned FileInfo describes the symbolic link. Lstat
// makes no attempt to follow the link. These semantics are identical to
// os.Lstat.
Lstat(name string) (os.FileInfo, error)
// Readlink returns the destination of the named symbolic link. These
// semantics are identical to os.Readlink.
Readlink(name string) (string, error)
}
// osVFS is the "nil" VFS, in that it just passes everything through to the os
// module.
type osVFS struct{}
// Lstat returns a FileInfo describing the named file. If the file is a
// symbolic link, the returned FileInfo describes the symbolic link. Lstat
// makes no attempt to follow the link. These semantics are identical to
// os.Lstat.
func (o osVFS) Lstat(name string) (os.FileInfo, error) { return os.Lstat(name) }
// Readlink returns the destination of the named symbolic link. These
// semantics are identical to os.Readlink.
func (o osVFS) Readlink(name string) (string, error) { return os.Readlink(name) }

View File

@ -1,4 +0,0 @@
The `contrib` directory contains scripts, images, and other helpful things
which are not part of the core docker distribution. Please note that they
could be out of date, since they do not receive the same attention as the
rest of the repository.

View File

@ -1,10 +0,0 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
printf("EUID=%d\n", geteuid());
return 0;
}

View File

@ -1,16 +0,0 @@
#define _GNU_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
int err = acct("/tmp/t");
if (err == -1) {
fprintf(stderr, "acct failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

View File

@ -1,7 +0,0 @@
.globl _start
.text
_start:
xorl %eax, %eax
incl %eax
movb $0, %bl
int $0x80

View File

@ -1,63 +0,0 @@
#define _GNU_SOURCE
#include <errno.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */
struct clone_args {
char **argv;
};
// child_exec is the func that will be executed as the result of clone
static int child_exec(void *stuff)
{
struct clone_args *args = (struct clone_args *)stuff;
if (execvp(args->argv[0], args->argv) != 0) {
fprintf(stderr, "failed to execvp arguments %s\n",
strerror(errno));
exit(-1);
}
// we should never reach here!
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
struct clone_args args;
args.argv = &argv[1];
int clone_flags = CLONE_NEWNS | CLONE_NEWPID | SIGCHLD;
// allocate stack for child
char *stack; /* Start of stack buffer */
char *child_stack; /* End of stack buffer */
stack =
mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANON | MAP_STACK, -1, 0);
if (stack == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
child_stack = stack + STACK_SIZE; /* Assume stack grows downward */
// the result of this call is that our child_exec will be run in another
// process returning its pid
pid_t pid = clone(child_exec, child_stack, clone_flags, &args);
if (pid < 0) {
fprintf(stderr, "clone failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// lets wait on our child process here before we, the parent, exits
if (waitpid(pid, NULL, 0) == -1) {
fprintf(stderr, "failed to wait pid %d\n", pid);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

View File

@ -1,14 +0,0 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
int main() {
if (socket(PF_INET, SOCK_RAW, IPPROTO_UDP) == -1) {
perror("socket");
return 1;
}
return 0;
}

View File

@ -1,11 +0,0 @@
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main() {
if (setgid(1) == -1) {
perror("setgid");
return 1;
}
return 0;
}

View File

@ -1,11 +0,0 @@
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main() {
if (setuid(1) == -1) {
perror("setuid");
return 1;
}
return 0;
}

View File

@ -1,30 +0,0 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int s;
struct sockaddr_in sin;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) {
perror("socket");
return 1;
}
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(80);
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
perror("bind");
return 1;
}
close(s);
return 0;
}

View File

@ -1,63 +0,0 @@
#define _GNU_SOURCE
#include <errno.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */
struct clone_args {
char **argv;
};
// child_exec is the func that will be executed as the result of clone
static int child_exec(void *stuff)
{
struct clone_args *args = (struct clone_args *)stuff;
if (execvp(args->argv[0], args->argv) != 0) {
fprintf(stderr, "failed to execvp arguments %s\n",
strerror(errno));
exit(-1);
}
// we should never reach here!
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
struct clone_args args;
args.argv = &argv[1];
int clone_flags = CLONE_NEWUSER | SIGCHLD;
// allocate stack for child
char *stack; /* Start of stack buffer */
char *child_stack; /* End of stack buffer */
stack =
mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANON | MAP_STACK, -1, 0);
if (stack == MAP_FAILED) {
fprintf(stderr, "mmap failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
child_stack = stack + STACK_SIZE; /* Assume stack grows downward */
// the result of this call is that our child_exec will be run in another
// process returning its pid
pid_t pid = clone(child_exec, child_stack, clone_flags, &args);
if (pid < 0) {
fprintf(stderr, "clone failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
// lets wait on our child process here before we, the parent, exits
if (waitpid(pid, NULL, 0) == -1) {
fprintf(stderr, "failed to wait pid %d\n", pid);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

View File

@ -1,350 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2017 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import (
"fmt"
"reflect"
"strings"
"sync"
"sync/atomic"
)
type generatedDiscarder interface {
XXX_DiscardUnknown()
}
// DiscardUnknown recursively discards all unknown fields from this message
// and all embedded messages.
//
// When unmarshaling a message with unrecognized fields, the tags and values
// of such fields are preserved in the Message. This allows a later call to
// marshal to be able to produce a message that continues to have those
// unrecognized fields. To avoid this, DiscardUnknown is used to
// explicitly clear the unknown fields after unmarshaling.
//
// For proto2 messages, the unknown fields of message extensions are only
// discarded from messages that have been accessed via GetExtension.
func DiscardUnknown(m Message) {
if m, ok := m.(generatedDiscarder); ok {
m.XXX_DiscardUnknown()
return
}
// TODO: Dynamically populate a InternalMessageInfo for legacy messages,
// but the master branch has no implementation for InternalMessageInfo,
// so it would be more work to replicate that approach.
discardLegacy(m)
}
// DiscardUnknown recursively discards all unknown fields.
func (a *InternalMessageInfo) DiscardUnknown(m Message) {
di := atomicLoadDiscardInfo(&a.discard)
if di == nil {
di = getDiscardInfo(reflect.TypeOf(m).Elem())
atomicStoreDiscardInfo(&a.discard, di)
}
di.discard(toPointer(&m))
}
type discardInfo struct {
typ reflect.Type
initialized int32 // 0: only typ is valid, 1: everything is valid
lock sync.Mutex
fields []discardFieldInfo
unrecognized field
}
type discardFieldInfo struct {
field field // Offset of field, guaranteed to be valid
discard func(src pointer)
}
var (
discardInfoMap = map[reflect.Type]*discardInfo{}
discardInfoLock sync.Mutex
)
func getDiscardInfo(t reflect.Type) *discardInfo {
discardInfoLock.Lock()
defer discardInfoLock.Unlock()
di := discardInfoMap[t]
if di == nil {
di = &discardInfo{typ: t}
discardInfoMap[t] = di
}
return di
}
func (di *discardInfo) discard(src pointer) {
if src.isNil() {
return // Nothing to do.
}
if atomic.LoadInt32(&di.initialized) == 0 {
di.computeDiscardInfo()
}
for _, fi := range di.fields {
sfp := src.offset(fi.field)
fi.discard(sfp)
}
// For proto2 messages, only discard unknown fields in message extensions
// that have been accessed via GetExtension.
if em, err := extendable(src.asPointerTo(di.typ).Interface()); err == nil {
// Ignore lock since DiscardUnknown is not concurrency safe.
emm, _ := em.extensionsRead()
for _, mx := range emm {
if m, ok := mx.value.(Message); ok {
DiscardUnknown(m)
}
}
}
if di.unrecognized.IsValid() {
*src.offset(di.unrecognized).toBytes() = nil
}
}
func (di *discardInfo) computeDiscardInfo() {
di.lock.Lock()
defer di.lock.Unlock()
if di.initialized != 0 {
return
}
t := di.typ
n := t.NumField()
for i := 0; i < n; i++ {
f := t.Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
continue
}
dfi := discardFieldInfo{field: toField(&f)}
tf := f.Type
// Unwrap tf to get its most basic type.
var isPointer, isSlice bool
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
isSlice = true
tf = tf.Elem()
}
if tf.Kind() == reflect.Ptr {
isPointer = true
tf = tf.Elem()
}
if isPointer && isSlice && tf.Kind() != reflect.Struct {
panic(fmt.Sprintf("%v.%s cannot be a slice of pointers to primitive types", t, f.Name))
}
switch tf.Kind() {
case reflect.Struct:
switch {
case !isPointer:
panic(fmt.Sprintf("%v.%s cannot be a direct struct value", t, f.Name))
case isSlice: // E.g., []*pb.T
di := getDiscardInfo(tf)
dfi.discard = func(src pointer) {
sps := src.getPointerSlice()
for _, sp := range sps {
if !sp.isNil() {
di.discard(sp)
}
}
}
default: // E.g., *pb.T
di := getDiscardInfo(tf)
dfi.discard = func(src pointer) {
sp := src.getPointer()
if !sp.isNil() {
di.discard(sp)
}
}
}
case reflect.Map:
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%v.%s cannot be a pointer to a map or a slice of map values", t, f.Name))
default: // E.g., map[K]V
if tf.Elem().Kind() == reflect.Ptr { // Proto struct (e.g., *T)
dfi.discard = func(src pointer) {
sm := src.asPointerTo(tf).Elem()
if sm.Len() == 0 {
return
}
for _, key := range sm.MapKeys() {
val := sm.MapIndex(key)
DiscardUnknown(val.Interface().(Message))
}
}
} else {
dfi.discard = func(pointer) {} // Noop
}
}
case reflect.Interface:
// Must be oneof field.
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%v.%s cannot be a pointer to a interface or a slice of interface values", t, f.Name))
default: // E.g., interface{}
// TODO: Make this faster?
dfi.discard = func(src pointer) {
su := src.asPointerTo(tf).Elem()
if !su.IsNil() {
sv := su.Elem().Elem().Field(0)
if sv.Kind() == reflect.Ptr && sv.IsNil() {
return
}
switch sv.Type().Kind() {
case reflect.Ptr: // Proto struct (e.g., *T)
DiscardUnknown(sv.Interface().(Message))
}
}
}
}
default:
continue
}
di.fields = append(di.fields, dfi)
}
di.unrecognized = invalidField
if f, ok := t.FieldByName("XXX_unrecognized"); ok {
if f.Type != reflect.TypeOf([]byte{}) {
panic("expected XXX_unrecognized to be of type []byte")
}
di.unrecognized = toField(&f)
}
atomic.StoreInt32(&di.initialized, 1)
}
func discardLegacy(m Message) {
v := reflect.ValueOf(m)
if v.Kind() != reflect.Ptr || v.IsNil() {
return
}
v = v.Elem()
if v.Kind() != reflect.Struct {
return
}
t := v.Type()
for i := 0; i < v.NumField(); i++ {
f := t.Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
continue
}
vf := v.Field(i)
tf := f.Type
// Unwrap tf to get its most basic type.
var isPointer, isSlice bool
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
isSlice = true
tf = tf.Elem()
}
if tf.Kind() == reflect.Ptr {
isPointer = true
tf = tf.Elem()
}
if isPointer && isSlice && tf.Kind() != reflect.Struct {
panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name))
}
switch tf.Kind() {
case reflect.Struct:
switch {
case !isPointer:
panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name))
case isSlice: // E.g., []*pb.T
for j := 0; j < vf.Len(); j++ {
discardLegacy(vf.Index(j).Interface().(Message))
}
default: // E.g., *pb.T
discardLegacy(vf.Interface().(Message))
}
case reflect.Map:
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name))
default: // E.g., map[K]V
tv := vf.Type().Elem()
if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T)
for _, key := range vf.MapKeys() {
val := vf.MapIndex(key)
discardLegacy(val.Interface().(Message))
}
}
}
case reflect.Interface:
// Must be oneof field.
switch {
case isPointer || isSlice:
panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name))
default: // E.g., test_proto.isCommunique_Union interface
if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" {
vf = vf.Elem() // E.g., *test_proto.Communique_Msg
if !vf.IsNil() {
vf = vf.Elem() // E.g., test_proto.Communique_Msg
vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value
if vf.Kind() == reflect.Ptr {
discardLegacy(vf.Interface().(Message))
}
}
}
}
}
}
if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() {
if vf.Type() != reflect.TypeOf([]byte{}) {
panic("expected XXX_unrecognized to be of type []byte")
}
vf.Set(reflect.ValueOf([]byte(nil)))
}
// For proto2 messages, only discard unknown fields in message extensions
// that have been accessed via GetExtension.
if em, err := extendable(m); err == nil {
// Ignore lock since discardLegacy is not concurrency safe.
emm, _ := em.extensionsRead()
for _, mx := range emm {
if m, ok := mx.value.(Message); ok {
discardLegacy(m)
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,654 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import (
"fmt"
"reflect"
"strings"
"sync"
"sync/atomic"
)
// Merge merges the src message into dst.
// This assumes that dst and src of the same type and are non-nil.
func (a *InternalMessageInfo) Merge(dst, src Message) {
mi := atomicLoadMergeInfo(&a.merge)
if mi == nil {
mi = getMergeInfo(reflect.TypeOf(dst).Elem())
atomicStoreMergeInfo(&a.merge, mi)
}
mi.merge(toPointer(&dst), toPointer(&src))
}
type mergeInfo struct {
typ reflect.Type
initialized int32 // 0: only typ is valid, 1: everything is valid
lock sync.Mutex
fields []mergeFieldInfo
unrecognized field // Offset of XXX_unrecognized
}
type mergeFieldInfo struct {
field field // Offset of field, guaranteed to be valid
// isPointer reports whether the value in the field is a pointer.
// This is true for the following situations:
// * Pointer to struct
// * Pointer to basic type (proto2 only)
// * Slice (first value in slice header is a pointer)
// * String (first value in string header is a pointer)
isPointer bool
// basicWidth reports the width of the field assuming that it is directly
// embedded in the struct (as is the case for basic types in proto3).
// The possible values are:
// 0: invalid
// 1: bool
// 4: int32, uint32, float32
// 8: int64, uint64, float64
basicWidth int
// Where dst and src are pointers to the types being merged.
merge func(dst, src pointer)
}
var (
mergeInfoMap = map[reflect.Type]*mergeInfo{}
mergeInfoLock sync.Mutex
)
func getMergeInfo(t reflect.Type) *mergeInfo {
mergeInfoLock.Lock()
defer mergeInfoLock.Unlock()
mi := mergeInfoMap[t]
if mi == nil {
mi = &mergeInfo{typ: t}
mergeInfoMap[t] = mi
}
return mi
}
// merge merges src into dst assuming they are both of type *mi.typ.
func (mi *mergeInfo) merge(dst, src pointer) {
if dst.isNil() {
panic("proto: nil destination")
}
if src.isNil() {
return // Nothing to do.
}
if atomic.LoadInt32(&mi.initialized) == 0 {
mi.computeMergeInfo()
}
for _, fi := range mi.fields {
sfp := src.offset(fi.field)
// As an optimization, we can avoid the merge function call cost
// if we know for sure that the source will have no effect
// by checking if it is the zero value.
if unsafeAllowed {
if fi.isPointer && sfp.getPointer().isNil() { // Could be slice or string
continue
}
if fi.basicWidth > 0 {
switch {
case fi.basicWidth == 1 && !*sfp.toBool():
continue
case fi.basicWidth == 4 && *sfp.toUint32() == 0:
continue
case fi.basicWidth == 8 && *sfp.toUint64() == 0:
continue
}
}
}
dfp := dst.offset(fi.field)
fi.merge(dfp, sfp)
}
// TODO: Make this faster?
out := dst.asPointerTo(mi.typ).Elem()
in := src.asPointerTo(mi.typ).Elem()
if emIn, err := extendable(in.Addr().Interface()); err == nil {
emOut, _ := extendable(out.Addr().Interface())
mIn, muIn := emIn.extensionsRead()
if mIn != nil {
mOut := emOut.extensionsWrite()
muIn.Lock()
mergeExtension(mOut, mIn)
muIn.Unlock()
}
}
if mi.unrecognized.IsValid() {
if b := *src.offset(mi.unrecognized).toBytes(); len(b) > 0 {
*dst.offset(mi.unrecognized).toBytes() = append([]byte(nil), b...)
}
}
}
func (mi *mergeInfo) computeMergeInfo() {
mi.lock.Lock()
defer mi.lock.Unlock()
if mi.initialized != 0 {
return
}
t := mi.typ
n := t.NumField()
props := GetProperties(t)
for i := 0; i < n; i++ {
f := t.Field(i)
if strings.HasPrefix(f.Name, "XXX_") {
continue
}
mfi := mergeFieldInfo{field: toField(&f)}
tf := f.Type
// As an optimization, we can avoid the merge function call cost
// if we know for sure that the source will have no effect
// by checking if it is the zero value.
if unsafeAllowed {
switch tf.Kind() {
case reflect.Ptr, reflect.Slice, reflect.String:
// As a special case, we assume slices and strings are pointers
// since we know that the first field in the SliceSlice or
// StringHeader is a data pointer.
mfi.isPointer = true
case reflect.Bool:
mfi.basicWidth = 1
case reflect.Int32, reflect.Uint32, reflect.Float32:
mfi.basicWidth = 4
case reflect.Int64, reflect.Uint64, reflect.Float64:
mfi.basicWidth = 8
}
}
// Unwrap tf to get at its most basic type.
var isPointer, isSlice bool
if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
isSlice = true
tf = tf.Elem()
}
if tf.Kind() == reflect.Ptr {
isPointer = true
tf = tf.Elem()
}
if isPointer && isSlice && tf.Kind() != reflect.Struct {
panic("both pointer and slice for basic type in " + tf.Name())
}
switch tf.Kind() {
case reflect.Int32:
switch {
case isSlice: // E.g., []int32
mfi.merge = func(dst, src pointer) {
// NOTE: toInt32Slice is not defined (see pointer_reflect.go).
/*
sfsp := src.toInt32Slice()
if *sfsp != nil {
dfsp := dst.toInt32Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []int64{}
}
}
*/
sfs := src.getInt32Slice()
if sfs != nil {
dfs := dst.getInt32Slice()
dfs = append(dfs, sfs...)
if dfs == nil {
dfs = []int32{}
}
dst.setInt32Slice(dfs)
}
}
case isPointer: // E.g., *int32
mfi.merge = func(dst, src pointer) {
// NOTE: toInt32Ptr is not defined (see pointer_reflect.go).
/*
sfpp := src.toInt32Ptr()
if *sfpp != nil {
dfpp := dst.toInt32Ptr()
if *dfpp == nil {
*dfpp = Int32(**sfpp)
} else {
**dfpp = **sfpp
}
}
*/
sfp := src.getInt32Ptr()
if sfp != nil {
dfp := dst.getInt32Ptr()
if dfp == nil {
dst.setInt32Ptr(*sfp)
} else {
*dfp = *sfp
}
}
}
default: // E.g., int32
mfi.merge = func(dst, src pointer) {
if v := *src.toInt32(); v != 0 {
*dst.toInt32() = v
}
}
}
case reflect.Int64:
switch {
case isSlice: // E.g., []int64
mfi.merge = func(dst, src pointer) {
sfsp := src.toInt64Slice()
if *sfsp != nil {
dfsp := dst.toInt64Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []int64{}
}
}
}
case isPointer: // E.g., *int64
mfi.merge = func(dst, src pointer) {
sfpp := src.toInt64Ptr()
if *sfpp != nil {
dfpp := dst.toInt64Ptr()
if *dfpp == nil {
*dfpp = Int64(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., int64
mfi.merge = func(dst, src pointer) {
if v := *src.toInt64(); v != 0 {
*dst.toInt64() = v
}
}
}
case reflect.Uint32:
switch {
case isSlice: // E.g., []uint32
mfi.merge = func(dst, src pointer) {
sfsp := src.toUint32Slice()
if *sfsp != nil {
dfsp := dst.toUint32Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []uint32{}
}
}
}
case isPointer: // E.g., *uint32
mfi.merge = func(dst, src pointer) {
sfpp := src.toUint32Ptr()
if *sfpp != nil {
dfpp := dst.toUint32Ptr()
if *dfpp == nil {
*dfpp = Uint32(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., uint32
mfi.merge = func(dst, src pointer) {
if v := *src.toUint32(); v != 0 {
*dst.toUint32() = v
}
}
}
case reflect.Uint64:
switch {
case isSlice: // E.g., []uint64
mfi.merge = func(dst, src pointer) {
sfsp := src.toUint64Slice()
if *sfsp != nil {
dfsp := dst.toUint64Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []uint64{}
}
}
}
case isPointer: // E.g., *uint64
mfi.merge = func(dst, src pointer) {
sfpp := src.toUint64Ptr()
if *sfpp != nil {
dfpp := dst.toUint64Ptr()
if *dfpp == nil {
*dfpp = Uint64(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., uint64
mfi.merge = func(dst, src pointer) {
if v := *src.toUint64(); v != 0 {
*dst.toUint64() = v
}
}
}
case reflect.Float32:
switch {
case isSlice: // E.g., []float32
mfi.merge = func(dst, src pointer) {
sfsp := src.toFloat32Slice()
if *sfsp != nil {
dfsp := dst.toFloat32Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []float32{}
}
}
}
case isPointer: // E.g., *float32
mfi.merge = func(dst, src pointer) {
sfpp := src.toFloat32Ptr()
if *sfpp != nil {
dfpp := dst.toFloat32Ptr()
if *dfpp == nil {
*dfpp = Float32(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., float32
mfi.merge = func(dst, src pointer) {
if v := *src.toFloat32(); v != 0 {
*dst.toFloat32() = v
}
}
}
case reflect.Float64:
switch {
case isSlice: // E.g., []float64
mfi.merge = func(dst, src pointer) {
sfsp := src.toFloat64Slice()
if *sfsp != nil {
dfsp := dst.toFloat64Slice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []float64{}
}
}
}
case isPointer: // E.g., *float64
mfi.merge = func(dst, src pointer) {
sfpp := src.toFloat64Ptr()
if *sfpp != nil {
dfpp := dst.toFloat64Ptr()
if *dfpp == nil {
*dfpp = Float64(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., float64
mfi.merge = func(dst, src pointer) {
if v := *src.toFloat64(); v != 0 {
*dst.toFloat64() = v
}
}
}
case reflect.Bool:
switch {
case isSlice: // E.g., []bool
mfi.merge = func(dst, src pointer) {
sfsp := src.toBoolSlice()
if *sfsp != nil {
dfsp := dst.toBoolSlice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []bool{}
}
}
}
case isPointer: // E.g., *bool
mfi.merge = func(dst, src pointer) {
sfpp := src.toBoolPtr()
if *sfpp != nil {
dfpp := dst.toBoolPtr()
if *dfpp == nil {
*dfpp = Bool(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., bool
mfi.merge = func(dst, src pointer) {
if v := *src.toBool(); v {
*dst.toBool() = v
}
}
}
case reflect.String:
switch {
case isSlice: // E.g., []string
mfi.merge = func(dst, src pointer) {
sfsp := src.toStringSlice()
if *sfsp != nil {
dfsp := dst.toStringSlice()
*dfsp = append(*dfsp, *sfsp...)
if *dfsp == nil {
*dfsp = []string{}
}
}
}
case isPointer: // E.g., *string
mfi.merge = func(dst, src pointer) {
sfpp := src.toStringPtr()
if *sfpp != nil {
dfpp := dst.toStringPtr()
if *dfpp == nil {
*dfpp = String(**sfpp)
} else {
**dfpp = **sfpp
}
}
}
default: // E.g., string
mfi.merge = func(dst, src pointer) {
if v := *src.toString(); v != "" {
*dst.toString() = v
}
}
}
case reflect.Slice:
isProto3 := props.Prop[i].proto3
switch {
case isPointer:
panic("bad pointer in byte slice case in " + tf.Name())
case tf.Elem().Kind() != reflect.Uint8:
panic("bad element kind in byte slice case in " + tf.Name())
case isSlice: // E.g., [][]byte
mfi.merge = func(dst, src pointer) {
sbsp := src.toBytesSlice()
if *sbsp != nil {
dbsp := dst.toBytesSlice()
for _, sb := range *sbsp {
if sb == nil {
*dbsp = append(*dbsp, nil)
} else {
*dbsp = append(*dbsp, append([]byte{}, sb...))
}
}
if *dbsp == nil {
*dbsp = [][]byte{}
}
}
}
default: // E.g., []byte
mfi.merge = func(dst, src pointer) {
sbp := src.toBytes()
if *sbp != nil {
dbp := dst.toBytes()
if !isProto3 || len(*sbp) > 0 {
*dbp = append([]byte{}, *sbp...)
}
}
}
}
case reflect.Struct:
switch {
case !isPointer:
panic(fmt.Sprintf("message field %s without pointer", tf))
case isSlice: // E.g., []*pb.T
mi := getMergeInfo(tf)
mfi.merge = func(dst, src pointer) {
sps := src.getPointerSlice()
if sps != nil {
dps := dst.getPointerSlice()
for _, sp := range sps {
var dp pointer
if !sp.isNil() {
dp = valToPointer(reflect.New(tf))
mi.merge(dp, sp)
}
dps = append(dps, dp)
}
if dps == nil {
dps = []pointer{}
}
dst.setPointerSlice(dps)
}
}
default: // E.g., *pb.T
mi := getMergeInfo(tf)
mfi.merge = func(dst, src pointer) {
sp := src.getPointer()
if !sp.isNil() {
dp := dst.getPointer()
if dp.isNil() {
dp = valToPointer(reflect.New(tf))
dst.setPointer(dp)
}
mi.merge(dp, sp)
}
}
}
case reflect.Map:
switch {
case isPointer || isSlice:
panic("bad pointer or slice in map case in " + tf.Name())
default: // E.g., map[K]V
mfi.merge = func(dst, src pointer) {
sm := src.asPointerTo(tf).Elem()
if sm.Len() == 0 {
return
}
dm := dst.asPointerTo(tf).Elem()
if dm.IsNil() {
dm.Set(reflect.MakeMap(tf))
}
switch tf.Elem().Kind() {
case reflect.Ptr: // Proto struct (e.g., *T)
for _, key := range sm.MapKeys() {
val := sm.MapIndex(key)
val = reflect.ValueOf(Clone(val.Interface().(Message)))
dm.SetMapIndex(key, val)
}
case reflect.Slice: // E.g. Bytes type (e.g., []byte)
for _, key := range sm.MapKeys() {
val := sm.MapIndex(key)
val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
dm.SetMapIndex(key, val)
}
default: // Basic type (e.g., string)
for _, key := range sm.MapKeys() {
val := sm.MapIndex(key)
dm.SetMapIndex(key, val)
}
}
}
}
case reflect.Interface:
// Must be oneof field.
switch {
case isPointer || isSlice:
panic("bad pointer or slice in interface case in " + tf.Name())
default: // E.g., interface{}
// TODO: Make this faster?
mfi.merge = func(dst, src pointer) {
su := src.asPointerTo(tf).Elem()
if !su.IsNil() {
du := dst.asPointerTo(tf).Elem()
typ := su.Elem().Type()
if du.IsNil() || du.Elem().Type() != typ {
du.Set(reflect.New(typ.Elem())) // Initialize interface if empty
}
sv := su.Elem().Elem().Field(0)
if sv.Kind() == reflect.Ptr && sv.IsNil() {
return
}
dv := du.Elem().Elem().Field(0)
if dv.Kind() == reflect.Ptr && dv.IsNil() {
dv.Set(reflect.New(sv.Type().Elem())) // Initialize proto message if empty
}
switch sv.Type().Kind() {
case reflect.Ptr: // Proto struct (e.g., *T)
Merge(dv.Interface().(Message), sv.Interface().(Message))
case reflect.Slice: // E.g. Bytes type (e.g., []byte)
dv.Set(reflect.ValueOf(append([]byte{}, sv.Bytes()...)))
default: // Basic type (e.g., string)
dv.Set(sv)
}
}
}
}
default:
panic(fmt.Sprintf("merger not found for type:%s", tf))
}
mi.fields = append(mi.fields, mfi)
}
mi.unrecognized = invalidField
if f, ok := t.FieldByName("XXX_unrecognized"); ok {
if f.Type != reflect.TypeOf([]byte{}) {
panic("expected XXX_unrecognized to be of type []byte")
}
mi.unrecognized = toField(&f)
}
atomic.StoreInt32(&mi.initialized, 1)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +0,0 @@
package mount
// GetMounts retrieves a list of mounts for the current running process.
func GetMounts() ([]*Info, error) {
return parseMountTable()
}
// Mounted looks at /proc/self/mountinfo to determine of the specified
// mountpoint has been mounted
func Mounted(mountpoint string) (bool, error) {
entries, err := parseMountTable()
if err != nil {
return false, err
}
// Search the table for the mountpoint
for _, e := range entries {
if e.Mountpoint == mountpoint {
return true, nil
}
}
return false, nil
}

View File

@ -1,82 +0,0 @@
// +build linux
package mount
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
const (
/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
(1) mount ID: unique identifier of the mount (may be reused after umount)
(2) parent ID: ID of parent (or of self for the top of the mount tree)
(3) major:minor: value of st_dev for files on filesystem
(4) root: root of the mount within the filesystem
(5) mount point: mount point relative to the process's root
(6) mount options: per mount options
(7) optional fields: zero or more fields of the form "tag[:value]"
(8) separator: marks the end of the optional fields
(9) filesystem type: name of filesystem of the form "type[.subtype]"
(10) mount source: filesystem specific information or "none"
(11) super options: per super block options*/
mountinfoFormat = "%d %d %d:%d %s %s %s %s"
)
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
// bind mounts
func parseMountTable() ([]*Info, error) {
f, err := os.Open("/proc/self/mountinfo")
if err != nil {
return nil, err
}
defer f.Close()
return parseInfoFile(f)
}
func parseInfoFile(r io.Reader) ([]*Info, error) {
var (
s = bufio.NewScanner(r)
out = []*Info{}
)
for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
var (
p = &Info{}
text = s.Text()
optionalFields string
)
if _, err := fmt.Sscanf(text, mountinfoFormat,
&p.ID, &p.Parent, &p.Major, &p.Minor,
&p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil {
return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
}
// Safe as mountinfo encodes mountpoints with spaces as \040.
index := strings.Index(text, " - ")
postSeparatorFields := strings.Fields(text[index+3:])
if len(postSeparatorFields) < 3 {
return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
}
if optionalFields != "-" {
p.Optional = optionalFields
}
p.Fstype = postSeparatorFields[0]
p.Source = postSeparatorFields[1]
p.VfsOpts = strings.Join(postSeparatorFields[2:], " ")
out = append(out, p)
}
return out, nil
}

View File

@ -1,40 +0,0 @@
package mount
// Info reveals information about a particular mounted filesystem. This
// struct is populated from the content in the /proc/<pid>/mountinfo file.
type Info struct {
// ID is a unique identifier of the mount (may be reused after umount).
ID int
// Parent indicates the ID of the mount parent (or of self for the top of the
// mount tree).
Parent int
// Major indicates one half of the device ID which identifies the device class.
Major int
// Minor indicates one half of the device ID which identifies a specific
// instance of device.
Minor int
// Root of the mount within the filesystem.
Root string
// Mountpoint indicates the mount point relative to the process's root.
Mountpoint string
// Opts represents mount-specific options.
Opts string
// Optional represents optional fields.
Optional string
// Fstype indicates the type of filesystem, such as EXT3.
Fstype string
// Source indicates filesystem specific information or "none".
Source string
// VfsOpts represents per super block options.
VfsOpts string
}

View File

@ -1,197 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code can be compiled and used to test the otr package against libotr.
// See otr_test.go.
// +build ignore
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <proto.h>
#include <message.h>
#include <privkey.h>
static int g_session_established = 0;
OtrlPolicy policy(void *opdata, ConnContext *context) {
return OTRL_POLICY_ALWAYS;
}
int is_logged_in(void *opdata, const char *accountname, const char *protocol,
const char *recipient) {
return 1;
}
void inject_message(void *opdata, const char *accountname, const char *protocol,
const char *recipient, const char *message) {
printf("%s\n", message);
fflush(stdout);
fprintf(stderr, "libotr helper sent: %s\n", message);
}
void update_context_list(void *opdata) {}
void new_fingerprint(void *opdata, OtrlUserState us, const char *accountname,
const char *protocol, const char *username,
unsigned char fingerprint[20]) {
fprintf(stderr, "NEW FINGERPRINT\n");
g_session_established = 1;
}
void write_fingerprints(void *opdata) {}
void gone_secure(void *opdata, ConnContext *context) {}
void gone_insecure(void *opdata, ConnContext *context) {}
void still_secure(void *opdata, ConnContext *context, int is_reply) {}
int max_message_size(void *opdata, ConnContext *context) { return 99999; }
const char *account_name(void *opdata, const char *account,
const char *protocol) {
return "ACCOUNT";
}
void account_name_free(void *opdata, const char *account_name) {}
const char *error_message(void *opdata, ConnContext *context,
OtrlErrorCode err_code) {
return "ERR";
}
void error_message_free(void *opdata, const char *msg) {}
void resent_msg_prefix_free(void *opdata, const char *prefix) {}
void handle_smp_event(void *opdata, OtrlSMPEvent smp_event,
ConnContext *context, unsigned short progress_event,
char *question) {}
void handle_msg_event(void *opdata, OtrlMessageEvent msg_event,
ConnContext *context, const char *message,
gcry_error_t err) {
fprintf(stderr, "msg event: %d %s\n", msg_event, message);
}
OtrlMessageAppOps uiops = {
policy,
NULL,
is_logged_in,
inject_message,
update_context_list,
new_fingerprint,
write_fingerprints,
gone_secure,
gone_insecure,
still_secure,
max_message_size,
account_name,
account_name_free,
NULL, /* received_symkey */
error_message,
error_message_free,
NULL, /* resent_msg_prefix */
resent_msg_prefix_free,
handle_smp_event,
handle_msg_event,
NULL /* create_instag */,
NULL /* convert_msg */,
NULL /* convert_free */,
NULL /* timer_control */,
};
static const char kPrivateKeyData[] =
"(privkeys (account (name \"account\") (protocol proto) (private-key (dsa "
"(p "
"#00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F"
"30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E"
"5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB"
"8C031D3561FECEE72EBB4A090D450A9B7A857#) (q "
"#00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#) (g "
"#535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F"
"1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F"
"6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57"
"597766A2F9CE3857D7ACE3E1E3BC1FC6F26#) (y "
"#0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF"
"2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93"
"454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A"
"3C0FF501E3DC673B76D7BABF349009B6ECF#) (x "
"#14D0345A3562C480A039E3C72764F72D79043216#)))))\n";
int main() {
OTRL_INIT;
// We have to write the private key information to a file because the libotr
// API demands a filename to read from.
const char *tmpdir = "/tmp";
if (getenv("TMP")) {
tmpdir = getenv("TMP");
}
char private_key_file[256];
snprintf(private_key_file, sizeof(private_key_file),
"%s/libotr_test_helper_privatekeys-XXXXXX", tmpdir);
int fd = mkstemp(private_key_file);
if (fd == -1) {
perror("creating temp file");
}
write(fd, kPrivateKeyData, sizeof(kPrivateKeyData) - 1);
close(fd);
OtrlUserState userstate = otrl_userstate_create();
otrl_privkey_read(userstate, private_key_file);
unlink(private_key_file);
fprintf(stderr, "libotr helper started\n");
char buf[4096];
for (;;) {
char *message = fgets(buf, sizeof(buf), stdin);
if (strlen(message) == 0) {
break;
}
message[strlen(message) - 1] = 0;
fprintf(stderr, "libotr helper got: %s\n", message);
char *newmessage = NULL;
OtrlTLV *tlvs;
int ignore_message = otrl_message_receiving(
userstate, &uiops, NULL, "account", "proto", "peer", message,
&newmessage, &tlvs, NULL, NULL, NULL);
if (tlvs) {
otrl_tlv_free(tlvs);
}
if (newmessage != NULL) {
fprintf(stderr, "libotr got: %s\n", newmessage);
otrl_message_free(newmessage);
gcry_error_t err;
char *newmessage = NULL;
err = otrl_message_sending(userstate, &uiops, NULL, "account", "proto",
"peer", 0, "test message", NULL, &newmessage,
OTRL_FRAGMENT_SEND_SKIP, NULL, NULL, NULL);
if (newmessage == NULL) {
fprintf(stderr, "libotr didn't encrypt message\n");
return 1;
}
write(1, newmessage, strlen(newmessage));
write(1, "\n", 1);
fprintf(stderr, "libotr sent: %s\n", newmessage);
otrl_message_free(newmessage);
g_session_established = 0;
write(1, "?OTRv2?\n", 8);
fprintf(stderr, "libotr sent: ?OTRv2\n");
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,572 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file implements the Socialist Millionaires Protocol as described in
// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html. The protocol
// specification is required in order to understand this code and, where
// possible, the variable names in the code match up with the spec.
package otr
import (
"bytes"
"crypto/sha256"
"errors"
"hash"
"math/big"
)
type smpFailure string
func (s smpFailure) Error() string {
return string(s)
}
var smpFailureError = smpFailure("otr: SMP protocol failed")
var smpSecretMissingError = smpFailure("otr: mutual secret needed")
const smpVersion = 1
const (
smpState1 = iota
smpState2
smpState3
smpState4
)
type smpState struct {
state int
a2, a3, b2, b3, pb, qb *big.Int
g2a, g3a *big.Int
g2, g3 *big.Int
g3b, papb, qaqb, ra *big.Int
saved *tlv
secret *big.Int
question string
}
func (c *Conversation) startSMP(question string) (tlvs []tlv) {
if c.smp.state != smpState1 {
tlvs = append(tlvs, c.generateSMPAbort())
}
tlvs = append(tlvs, c.generateSMP1(question))
c.smp.question = ""
c.smp.state = smpState2
return
}
func (c *Conversation) resetSMP() {
c.smp.state = smpState1
c.smp.secret = nil
c.smp.question = ""
}
func (c *Conversation) processSMP(in tlv) (out tlv, complete bool, err error) {
data := in.data
switch in.typ {
case tlvTypeSMPAbort:
if c.smp.state != smpState1 {
err = smpFailureError
}
c.resetSMP()
return
case tlvTypeSMP1WithQuestion:
// We preprocess this into a SMP1 message.
nulPos := bytes.IndexByte(data, 0)
if nulPos == -1 {
err = errors.New("otr: SMP message with question didn't contain a NUL byte")
return
}
c.smp.question = string(data[:nulPos])
data = data[nulPos+1:]
}
numMPIs, data, ok := getU32(data)
if !ok || numMPIs > 20 {
err = errors.New("otr: corrupt SMP message")
return
}
mpis := make([]*big.Int, numMPIs)
for i := range mpis {
var ok bool
mpis[i], data, ok = getMPI(data)
if !ok {
err = errors.New("otr: corrupt SMP message")
return
}
}
switch in.typ {
case tlvTypeSMP1, tlvTypeSMP1WithQuestion:
if c.smp.state != smpState1 {
c.resetSMP()
out = c.generateSMPAbort()
return
}
if c.smp.secret == nil {
err = smpSecretMissingError
return
}
if err = c.processSMP1(mpis); err != nil {
return
}
c.smp.state = smpState3
out = c.generateSMP2()
case tlvTypeSMP2:
if c.smp.state != smpState2 {
c.resetSMP()
out = c.generateSMPAbort()
return
}
if out, err = c.processSMP2(mpis); err != nil {
out = c.generateSMPAbort()
return
}
c.smp.state = smpState4
case tlvTypeSMP3:
if c.smp.state != smpState3 {
c.resetSMP()
out = c.generateSMPAbort()
return
}
if out, err = c.processSMP3(mpis); err != nil {
return
}
c.smp.state = smpState1
c.smp.secret = nil
complete = true
case tlvTypeSMP4:
if c.smp.state != smpState4 {
c.resetSMP()
out = c.generateSMPAbort()
return
}
if err = c.processSMP4(mpis); err != nil {
out = c.generateSMPAbort()
return
}
c.smp.state = smpState1
c.smp.secret = nil
complete = true
default:
panic("unknown SMP message")
}
return
}
func (c *Conversation) calcSMPSecret(mutualSecret []byte, weStarted bool) {
h := sha256.New()
h.Write([]byte{smpVersion})
if weStarted {
h.Write(c.PrivateKey.PublicKey.Fingerprint())
h.Write(c.TheirPublicKey.Fingerprint())
} else {
h.Write(c.TheirPublicKey.Fingerprint())
h.Write(c.PrivateKey.PublicKey.Fingerprint())
}
h.Write(c.SSID[:])
h.Write(mutualSecret)
c.smp.secret = new(big.Int).SetBytes(h.Sum(nil))
}
func (c *Conversation) generateSMP1(question string) tlv {
var randBuf [16]byte
c.smp.a2 = c.randMPI(randBuf[:])
c.smp.a3 = c.randMPI(randBuf[:])
g2a := new(big.Int).Exp(g, c.smp.a2, p)
g3a := new(big.Int).Exp(g, c.smp.a3, p)
h := sha256.New()
r2 := c.randMPI(randBuf[:])
r := new(big.Int).Exp(g, r2, p)
c2 := new(big.Int).SetBytes(hashMPIs(h, 1, r))
d2 := new(big.Int).Mul(c.smp.a2, c2)
d2.Sub(r2, d2)
d2.Mod(d2, q)
if d2.Sign() < 0 {
d2.Add(d2, q)
}
r3 := c.randMPI(randBuf[:])
r.Exp(g, r3, p)
c3 := new(big.Int).SetBytes(hashMPIs(h, 2, r))
d3 := new(big.Int).Mul(c.smp.a3, c3)
d3.Sub(r3, d3)
d3.Mod(d3, q)
if d3.Sign() < 0 {
d3.Add(d3, q)
}
var ret tlv
if len(question) > 0 {
ret.typ = tlvTypeSMP1WithQuestion
ret.data = append(ret.data, question...)
ret.data = append(ret.data, 0)
} else {
ret.typ = tlvTypeSMP1
}
ret.data = appendU32(ret.data, 6)
ret.data = appendMPIs(ret.data, g2a, c2, d2, g3a, c3, d3)
return ret
}
func (c *Conversation) processSMP1(mpis []*big.Int) error {
if len(mpis) != 6 {
return errors.New("otr: incorrect number of arguments in SMP1 message")
}
g2a := mpis[0]
c2 := mpis[1]
d2 := mpis[2]
g3a := mpis[3]
c3 := mpis[4]
d3 := mpis[5]
h := sha256.New()
r := new(big.Int).Exp(g, d2, p)
s := new(big.Int).Exp(g2a, c2, p)
r.Mul(r, s)
r.Mod(r, p)
t := new(big.Int).SetBytes(hashMPIs(h, 1, r))
if c2.Cmp(t) != 0 {
return errors.New("otr: ZKP c2 incorrect in SMP1 message")
}
r.Exp(g, d3, p)
s.Exp(g3a, c3, p)
r.Mul(r, s)
r.Mod(r, p)
t.SetBytes(hashMPIs(h, 2, r))
if c3.Cmp(t) != 0 {
return errors.New("otr: ZKP c3 incorrect in SMP1 message")
}
c.smp.g2a = g2a
c.smp.g3a = g3a
return nil
}
func (c *Conversation) generateSMP2() tlv {
var randBuf [16]byte
b2 := c.randMPI(randBuf[:])
c.smp.b3 = c.randMPI(randBuf[:])
r2 := c.randMPI(randBuf[:])
r3 := c.randMPI(randBuf[:])
r4 := c.randMPI(randBuf[:])
r5 := c.randMPI(randBuf[:])
r6 := c.randMPI(randBuf[:])
g2b := new(big.Int).Exp(g, b2, p)
g3b := new(big.Int).Exp(g, c.smp.b3, p)
r := new(big.Int).Exp(g, r2, p)
h := sha256.New()
c2 := new(big.Int).SetBytes(hashMPIs(h, 3, r))
d2 := new(big.Int).Mul(b2, c2)
d2.Sub(r2, d2)
d2.Mod(d2, q)
if d2.Sign() < 0 {
d2.Add(d2, q)
}
r.Exp(g, r3, p)
c3 := new(big.Int).SetBytes(hashMPIs(h, 4, r))
d3 := new(big.Int).Mul(c.smp.b3, c3)
d3.Sub(r3, d3)
d3.Mod(d3, q)
if d3.Sign() < 0 {
d3.Add(d3, q)
}
c.smp.g2 = new(big.Int).Exp(c.smp.g2a, b2, p)
c.smp.g3 = new(big.Int).Exp(c.smp.g3a, c.smp.b3, p)
c.smp.pb = new(big.Int).Exp(c.smp.g3, r4, p)
c.smp.qb = new(big.Int).Exp(g, r4, p)
r.Exp(c.smp.g2, c.smp.secret, p)
c.smp.qb.Mul(c.smp.qb, r)
c.smp.qb.Mod(c.smp.qb, p)
s := new(big.Int)
s.Exp(c.smp.g2, r6, p)
r.Exp(g, r5, p)
s.Mul(r, s)
s.Mod(s, p)
r.Exp(c.smp.g3, r5, p)
cp := new(big.Int).SetBytes(hashMPIs(h, 5, r, s))
// D5 = r5 - r4 cP mod q and D6 = r6 - y cP mod q
s.Mul(r4, cp)
r.Sub(r5, s)
d5 := new(big.Int).Mod(r, q)
if d5.Sign() < 0 {
d5.Add(d5, q)
}
s.Mul(c.smp.secret, cp)
r.Sub(r6, s)
d6 := new(big.Int).Mod(r, q)
if d6.Sign() < 0 {
d6.Add(d6, q)
}
var ret tlv
ret.typ = tlvTypeSMP2
ret.data = appendU32(ret.data, 11)
ret.data = appendMPIs(ret.data, g2b, c2, d2, g3b, c3, d3, c.smp.pb, c.smp.qb, cp, d5, d6)
return ret
}
func (c *Conversation) processSMP2(mpis []*big.Int) (out tlv, err error) {
if len(mpis) != 11 {
err = errors.New("otr: incorrect number of arguments in SMP2 message")
return
}
g2b := mpis[0]
c2 := mpis[1]
d2 := mpis[2]
g3b := mpis[3]
c3 := mpis[4]
d3 := mpis[5]
pb := mpis[6]
qb := mpis[7]
cp := mpis[8]
d5 := mpis[9]
d6 := mpis[10]
h := sha256.New()
r := new(big.Int).Exp(g, d2, p)
s := new(big.Int).Exp(g2b, c2, p)
r.Mul(r, s)
r.Mod(r, p)
s.SetBytes(hashMPIs(h, 3, r))
if c2.Cmp(s) != 0 {
err = errors.New("otr: ZKP c2 failed in SMP2 message")
return
}
r.Exp(g, d3, p)
s.Exp(g3b, c3, p)
r.Mul(r, s)
r.Mod(r, p)
s.SetBytes(hashMPIs(h, 4, r))
if c3.Cmp(s) != 0 {
err = errors.New("otr: ZKP c3 failed in SMP2 message")
return
}
c.smp.g2 = new(big.Int).Exp(g2b, c.smp.a2, p)
c.smp.g3 = new(big.Int).Exp(g3b, c.smp.a3, p)
r.Exp(g, d5, p)
s.Exp(c.smp.g2, d6, p)
r.Mul(r, s)
s.Exp(qb, cp, p)
r.Mul(r, s)
r.Mod(r, p)
s.Exp(c.smp.g3, d5, p)
t := new(big.Int).Exp(pb, cp, p)
s.Mul(s, t)
s.Mod(s, p)
t.SetBytes(hashMPIs(h, 5, s, r))
if cp.Cmp(t) != 0 {
err = errors.New("otr: ZKP cP failed in SMP2 message")
return
}
var randBuf [16]byte
r4 := c.randMPI(randBuf[:])
r5 := c.randMPI(randBuf[:])
r6 := c.randMPI(randBuf[:])
r7 := c.randMPI(randBuf[:])
pa := new(big.Int).Exp(c.smp.g3, r4, p)
r.Exp(c.smp.g2, c.smp.secret, p)
qa := new(big.Int).Exp(g, r4, p)
qa.Mul(qa, r)
qa.Mod(qa, p)
r.Exp(g, r5, p)
s.Exp(c.smp.g2, r6, p)
r.Mul(r, s)
r.Mod(r, p)
s.Exp(c.smp.g3, r5, p)
cp.SetBytes(hashMPIs(h, 6, s, r))
r.Mul(r4, cp)
d5 = new(big.Int).Sub(r5, r)
d5.Mod(d5, q)
if d5.Sign() < 0 {
d5.Add(d5, q)
}
r.Mul(c.smp.secret, cp)
d6 = new(big.Int).Sub(r6, r)
d6.Mod(d6, q)
if d6.Sign() < 0 {
d6.Add(d6, q)
}
r.ModInverse(qb, p)
qaqb := new(big.Int).Mul(qa, r)
qaqb.Mod(qaqb, p)
ra := new(big.Int).Exp(qaqb, c.smp.a3, p)
r.Exp(qaqb, r7, p)
s.Exp(g, r7, p)
cr := new(big.Int).SetBytes(hashMPIs(h, 7, s, r))
r.Mul(c.smp.a3, cr)
d7 := new(big.Int).Sub(r7, r)
d7.Mod(d7, q)
if d7.Sign() < 0 {
d7.Add(d7, q)
}
c.smp.g3b = g3b
c.smp.qaqb = qaqb
r.ModInverse(pb, p)
c.smp.papb = new(big.Int).Mul(pa, r)
c.smp.papb.Mod(c.smp.papb, p)
c.smp.ra = ra
out.typ = tlvTypeSMP3
out.data = appendU32(out.data, 8)
out.data = appendMPIs(out.data, pa, qa, cp, d5, d6, ra, cr, d7)
return
}
func (c *Conversation) processSMP3(mpis []*big.Int) (out tlv, err error) {
if len(mpis) != 8 {
err = errors.New("otr: incorrect number of arguments in SMP3 message")
return
}
pa := mpis[0]
qa := mpis[1]
cp := mpis[2]
d5 := mpis[3]
d6 := mpis[4]
ra := mpis[5]
cr := mpis[6]
d7 := mpis[7]
h := sha256.New()
r := new(big.Int).Exp(g, d5, p)
s := new(big.Int).Exp(c.smp.g2, d6, p)
r.Mul(r, s)
s.Exp(qa, cp, p)
r.Mul(r, s)
r.Mod(r, p)
s.Exp(c.smp.g3, d5, p)
t := new(big.Int).Exp(pa, cp, p)
s.Mul(s, t)
s.Mod(s, p)
t.SetBytes(hashMPIs(h, 6, s, r))
if t.Cmp(cp) != 0 {
err = errors.New("otr: ZKP cP failed in SMP3 message")
return
}
r.ModInverse(c.smp.qb, p)
qaqb := new(big.Int).Mul(qa, r)
qaqb.Mod(qaqb, p)
r.Exp(qaqb, d7, p)
s.Exp(ra, cr, p)
r.Mul(r, s)
r.Mod(r, p)
s.Exp(g, d7, p)
t.Exp(c.smp.g3a, cr, p)
s.Mul(s, t)
s.Mod(s, p)
t.SetBytes(hashMPIs(h, 7, s, r))
if t.Cmp(cr) != 0 {
err = errors.New("otr: ZKP cR failed in SMP3 message")
return
}
var randBuf [16]byte
r7 := c.randMPI(randBuf[:])
rb := new(big.Int).Exp(qaqb, c.smp.b3, p)
r.Exp(qaqb, r7, p)
s.Exp(g, r7, p)
cr = new(big.Int).SetBytes(hashMPIs(h, 8, s, r))
r.Mul(c.smp.b3, cr)
d7 = new(big.Int).Sub(r7, r)
d7.Mod(d7, q)
if d7.Sign() < 0 {
d7.Add(d7, q)
}
out.typ = tlvTypeSMP4
out.data = appendU32(out.data, 3)
out.data = appendMPIs(out.data, rb, cr, d7)
r.ModInverse(c.smp.pb, p)
r.Mul(pa, r)
r.Mod(r, p)
s.Exp(ra, c.smp.b3, p)
if r.Cmp(s) != 0 {
err = smpFailureError
}
return
}
func (c *Conversation) processSMP4(mpis []*big.Int) error {
if len(mpis) != 3 {
return errors.New("otr: incorrect number of arguments in SMP4 message")
}
rb := mpis[0]
cr := mpis[1]
d7 := mpis[2]
h := sha256.New()
r := new(big.Int).Exp(c.smp.qaqb, d7, p)
s := new(big.Int).Exp(rb, cr, p)
r.Mul(r, s)
r.Mod(r, p)
s.Exp(g, d7, p)
t := new(big.Int).Exp(c.smp.g3b, cr, p)
s.Mul(s, t)
s.Mod(s, p)
t.SetBytes(hashMPIs(h, 8, s, r))
if t.Cmp(cr) != 0 {
return errors.New("otr: ZKP cR failed in SMP4 message")
}
r.Exp(rb, c.smp.a3, p)
if r.Cmp(c.smp.papb) != 0 {
return smpFailureError
}
return nil
}
func (c *Conversation) generateSMPAbort() tlv {
return tlv{typ: tlvTypeSMPAbort}
}
func hashMPIs(h hash.Hash, magic byte, mpis ...*big.Int) []byte {
if h != nil {
h.Reset()
} else {
h = sha256.New()
}
h.Write([]byte{magic})
for _, mpi := range mpis {
h.Write(appendMPI(nil, mpi))
}
return h.Sum(nil)
}

View File

@ -1,7 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package test contains integration tests for the
// golang.org/x/crypto/ssh package.
package test // import "golang.org/x/crypto/ssh/test"

View File

@ -1,173 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// sshd_test_pw.c
// Wrapper to inject test password data for sshd PAM authentication
//
// This wrapper implements custom versions of getpwnam, getpwnam_r,
// getspnam and getspnam_r. These functions first call their real
// libc versions, then check if the requested user matches test user
// specified in env variable TEST_USER and if so replace the password
// with crypted() value of TEST_PASSWD env variable.
//
// Compile:
// gcc -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
//
// Compile with debug:
// gcc -DVERBOSE -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
//
// Run sshd:
// LD_PRELOAD="sshd_test_pw.so" TEST_USER="..." TEST_PASSWD="..." sshd ...
// +build ignore
#define _GNU_SOURCE
#include <string.h>
#include <pwd.h>
#include <shadow.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#ifdef VERBOSE
#define DEBUG(X...) fprintf(stderr, X)
#else
#define DEBUG(X...) while (0) { }
#endif
/* crypt() password */
static char *
pwhash(char *passwd) {
return strdup(crypt(passwd, "$6$"));
}
/* Pointers to real functions in libc */
static struct passwd * (*real_getpwnam)(const char *) = NULL;
static int (*real_getpwnam_r)(const char *, struct passwd *, char *, size_t, struct passwd **) = NULL;
static struct spwd * (*real_getspnam)(const char *) = NULL;
static int (*real_getspnam_r)(const char *, struct spwd *, char *, size_t, struct spwd **) = NULL;
/* Cached test user and test password */
static char *test_user = NULL;
static char *test_passwd_hash = NULL;
static void
init(void) {
/* Fetch real libc function pointers */
real_getpwnam = dlsym(RTLD_NEXT, "getpwnam");
real_getpwnam_r = dlsym(RTLD_NEXT, "getpwnam_r");
real_getspnam = dlsym(RTLD_NEXT, "getspnam");
real_getspnam_r = dlsym(RTLD_NEXT, "getspnam_r");
/* abort if env variables are not defined */
if (getenv("TEST_USER") == NULL || getenv("TEST_PASSWD") == NULL) {
fprintf(stderr, "env variables TEST_USER and TEST_PASSWD are missing\n");
abort();
}
/* Fetch test user and test password from env */
test_user = strdup(getenv("TEST_USER"));
test_passwd_hash = pwhash(getenv("TEST_PASSWD"));
DEBUG("sshd_test_pw init():\n");
DEBUG("\treal_getpwnam: %p\n", real_getpwnam);
DEBUG("\treal_getpwnam_r: %p\n", real_getpwnam_r);
DEBUG("\treal_getspnam: %p\n", real_getspnam);
DEBUG("\treal_getspnam_r: %p\n", real_getspnam_r);
DEBUG("\tTEST_USER: '%s'\n", test_user);
DEBUG("\tTEST_PASSWD: '%s'\n", getenv("TEST_PASSWD"));
DEBUG("\tTEST_PASSWD_HASH: '%s'\n", test_passwd_hash);
}
static int
is_test_user(const char *name) {
if (test_user != NULL && strcmp(test_user, name) == 0)
return 1;
return 0;
}
/* getpwnam */
struct passwd *
getpwnam(const char *name) {
struct passwd *pw;
DEBUG("sshd_test_pw getpwnam(%s)\n", name);
if (real_getpwnam == NULL)
init();
if ((pw = real_getpwnam(name)) == NULL)
return NULL;
if (is_test_user(name))
pw->pw_passwd = strdup(test_passwd_hash);
return pw;
}
/* getpwnam_r */
int
getpwnam_r(const char *name,
struct passwd *pwd,
char *buf,
size_t buflen,
struct passwd **result) {
int r;
DEBUG("sshd_test_pw getpwnam_r(%s)\n", name);
if (real_getpwnam_r == NULL)
init();
if ((r = real_getpwnam_r(name, pwd, buf, buflen, result)) != 0 || *result == NULL)
return r;
if (is_test_user(name))
pwd->pw_passwd = strdup(test_passwd_hash);
return 0;
}
/* getspnam */
struct spwd *
getspnam(const char *name) {
struct spwd *sp;
DEBUG("sshd_test_pw getspnam(%s)\n", name);
if (real_getspnam == NULL)
init();
if ((sp = real_getspnam(name)) == NULL)
return NULL;
if (is_test_user(name))
sp->sp_pwdp = strdup(test_passwd_hash);
return sp;
}
/* getspnam_r */
int
getspnam_r(const char *name,
struct spwd *spbuf,
char *buf,
size_t buflen,
struct spwd **spbufp) {
int r;
DEBUG("sshd_test_pw getspnam_r(%s)\n", name);
if (real_getspnam_r == NULL)
init();
if ((r = real_getspnam_r(name, spbuf, buf, buflen, spbufp)) != 0)
return r;
if (is_test_user(name))
spbuf->sp_pwdp = strdup(test_passwd_hash);
return r;
}

View File

@ -0,0 +1,11 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
TEXT ·socketcall(SB),NOSPLIT,$0-36
JMP syscall·socketcall(SB)
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
JMP syscall·rawsocketcall(SB)

View File

@ -1,48 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package svc
import (
"errors"
"golang.org/x/sys/windows"
)
// event represents auto-reset, initially non-signaled Windows event.
// It is used to communicate between go and asm parts of this package.
type event struct {
h windows.Handle
}
func newEvent() (*event, error) {
h, err := windows.CreateEvent(nil, 0, 0, nil)
if err != nil {
return nil, err
}
return &event{h: h}, nil
}
func (e *event) Close() error {
return windows.CloseHandle(e.h)
}
func (e *event) Set() error {
return windows.SetEvent(e.h)
}
func (e *event) Wait() error {
s, err := windows.WaitForSingleObject(e.h, windows.INFINITE)
switch s {
case windows.WAIT_OBJECT_0:
break
case windows.WAIT_FAILED:
return err
default:
return errors.New("unexpected result from WaitForSingleObject")
}
return nil
}

View File

@ -1,24 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// +build !go1.3
// copied from pkg/runtime
typedef unsigned int uint32;
typedef unsigned long long int uint64;
#ifdef _64BIT
typedef uint64 uintptr;
#else
typedef uint32 uintptr;
#endif
// from sys_386.s or sys_amd64.s
void ·servicemain(void);
void
·getServiceMain(uintptr *r)
{
*r = (uintptr)·servicemain;
}

View File

@ -1,11 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// +build !go1.3
package svc
// from go12.c
func getServiceMain(r *uintptr)

View File

@ -1,31 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// +build go1.3
package svc
import "unsafe"
const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
// Should be a built-in for unsafe.Pointer?
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
return unsafe.Pointer(uintptr(p) + x)
}
// funcPC returns the entry PC of the function f.
// It assumes that f is a func value. Otherwise the behavior is undefined.
func funcPC(f interface{}) uintptr {
return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
}
// from sys_386.s and sys_amd64.s
func servicectlhandler(ctl uint32) uintptr
func servicemain(argc uint32, argv **uint16)
func getServiceMain(r *uintptr) {
*r = funcPC(servicemain)
}

View File

@ -1,62 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package svc
import (
"unsafe"
"golang.org/x/sys/windows"
)
func allocSid(subAuth0 uint32) (*windows.SID, error) {
var sid *windows.SID
err := windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY,
1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid)
if err != nil {
return nil, err
}
return sid, nil
}
// IsAnInteractiveSession determines if calling process is running interactively.
// It queries the process token for membership in the Interactive group.
// http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s
func IsAnInteractiveSession() (bool, error) {
interSid, err := allocSid(windows.SECURITY_INTERACTIVE_RID)
if err != nil {
return false, err
}
defer windows.FreeSid(interSid)
serviceSid, err := allocSid(windows.SECURITY_SERVICE_RID)
if err != nil {
return false, err
}
defer windows.FreeSid(serviceSid)
t, err := windows.OpenCurrentProcessToken()
if err != nil {
return false, err
}
defer t.Close()
gs, err := t.GetTokenGroups()
if err != nil {
return false, err
}
p := unsafe.Pointer(&gs.Groups[0])
groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount]
for _, g := range groups {
if windows.EqualSid(g.Sid, interSid) {
return true, nil
}
if windows.EqualSid(g.Sid, serviceSid) {
return false, nil
}
}
return false, nil
}

View File

@ -1,363 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// Package svc provides everything required to build Windows service.
//
package svc
import (
"errors"
"runtime"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// State describes service execution state (Stopped, Running and so on).
type State uint32
const (
Stopped = State(windows.SERVICE_STOPPED)
StartPending = State(windows.SERVICE_START_PENDING)
StopPending = State(windows.SERVICE_STOP_PENDING)
Running = State(windows.SERVICE_RUNNING)
ContinuePending = State(windows.SERVICE_CONTINUE_PENDING)
PausePending = State(windows.SERVICE_PAUSE_PENDING)
Paused = State(windows.SERVICE_PAUSED)
)
// Cmd represents service state change request. It is sent to a service
// by the service manager, and should be actioned upon by the service.
type Cmd uint32
const (
Stop = Cmd(windows.SERVICE_CONTROL_STOP)
Pause = Cmd(windows.SERVICE_CONTROL_PAUSE)
Continue = Cmd(windows.SERVICE_CONTROL_CONTINUE)
Interrogate = Cmd(windows.SERVICE_CONTROL_INTERROGATE)
Shutdown = Cmd(windows.SERVICE_CONTROL_SHUTDOWN)
ParamChange = Cmd(windows.SERVICE_CONTROL_PARAMCHANGE)
NetBindAdd = Cmd(windows.SERVICE_CONTROL_NETBINDADD)
NetBindRemove = Cmd(windows.SERVICE_CONTROL_NETBINDREMOVE)
NetBindEnable = Cmd(windows.SERVICE_CONTROL_NETBINDENABLE)
NetBindDisable = Cmd(windows.SERVICE_CONTROL_NETBINDDISABLE)
DeviceEvent = Cmd(windows.SERVICE_CONTROL_DEVICEEVENT)
HardwareProfileChange = Cmd(windows.SERVICE_CONTROL_HARDWAREPROFILECHANGE)
PowerEvent = Cmd(windows.SERVICE_CONTROL_POWEREVENT)
SessionChange = Cmd(windows.SERVICE_CONTROL_SESSIONCHANGE)
)
// Accepted is used to describe commands accepted by the service.
// Note that Interrogate is always accepted.
type Accepted uint32
const (
AcceptStop = Accepted(windows.SERVICE_ACCEPT_STOP)
AcceptShutdown = Accepted(windows.SERVICE_ACCEPT_SHUTDOWN)
AcceptPauseAndContinue = Accepted(windows.SERVICE_ACCEPT_PAUSE_CONTINUE)
AcceptParamChange = Accepted(windows.SERVICE_ACCEPT_PARAMCHANGE)
AcceptNetBindChange = Accepted(windows.SERVICE_ACCEPT_NETBINDCHANGE)
AcceptHardwareProfileChange = Accepted(windows.SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
AcceptPowerEvent = Accepted(windows.SERVICE_ACCEPT_POWEREVENT)
AcceptSessionChange = Accepted(windows.SERVICE_ACCEPT_SESSIONCHANGE)
)
// Status combines State and Accepted commands to fully describe running service.
type Status struct {
State State
Accepts Accepted
CheckPoint uint32 // used to report progress during a lengthy operation
WaitHint uint32 // estimated time required for a pending operation, in milliseconds
}
// ChangeRequest is sent to the service Handler to request service status change.
type ChangeRequest struct {
Cmd Cmd
EventType uint32
EventData uintptr
CurrentStatus Status
}
// Handler is the interface that must be implemented to build Windows service.
type Handler interface {
// Execute will be called by the package code at the start of
// the service, and the service will exit once Execute completes.
// Inside Execute you must read service change requests from r and
// act accordingly. You must keep service control manager up to date
// about state of your service by writing into s as required.
// args contains service name followed by argument strings passed
// to the service.
// You can provide service exit code in exitCode return parameter,
// with 0 being "no error". You can also indicate if exit code,
// if any, is service specific or not by using svcSpecificEC
// parameter.
Execute(args []string, r <-chan ChangeRequest, s chan<- Status) (svcSpecificEC bool, exitCode uint32)
}
var (
// These are used by asm code.
goWaitsH uintptr
cWaitsH uintptr
ssHandle uintptr
sName *uint16
sArgc uintptr
sArgv **uint16
ctlHandlerExProc uintptr
cSetEvent uintptr
cWaitForSingleObject uintptr
cRegisterServiceCtrlHandlerExW uintptr
)
func init() {
k := syscall.MustLoadDLL("kernel32.dll")
cSetEvent = k.MustFindProc("SetEvent").Addr()
cWaitForSingleObject = k.MustFindProc("WaitForSingleObject").Addr()
a := syscall.MustLoadDLL("advapi32.dll")
cRegisterServiceCtrlHandlerExW = a.MustFindProc("RegisterServiceCtrlHandlerExW").Addr()
}
// The HandlerEx prototype also has a context pointer but since we don't use
// it at start-up time we don't have to pass it over either.
type ctlEvent struct {
cmd Cmd
eventType uint32
eventData uintptr
errno uint32
}
// service provides access to windows service api.
type service struct {
name string
h windows.Handle
cWaits *event
goWaits *event
c chan ctlEvent
handler Handler
}
func newService(name string, handler Handler) (*service, error) {
var s service
var err error
s.name = name
s.c = make(chan ctlEvent)
s.handler = handler
s.cWaits, err = newEvent()
if err != nil {
return nil, err
}
s.goWaits, err = newEvent()
if err != nil {
s.cWaits.Close()
return nil, err
}
return &s, nil
}
func (s *service) close() error {
s.cWaits.Close()
s.goWaits.Close()
return nil
}
type exitCode struct {
isSvcSpecific bool
errno uint32
}
func (s *service) updateStatus(status *Status, ec *exitCode) error {
if s.h == 0 {
return errors.New("updateStatus with no service status handle")
}
var t windows.SERVICE_STATUS
t.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
t.CurrentState = uint32(status.State)
if status.Accepts&AcceptStop != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_STOP
}
if status.Accepts&AcceptShutdown != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_SHUTDOWN
}
if status.Accepts&AcceptPauseAndContinue != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_PAUSE_CONTINUE
}
if status.Accepts&AcceptParamChange != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_PARAMCHANGE
}
if status.Accepts&AcceptNetBindChange != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_NETBINDCHANGE
}
if status.Accepts&AcceptHardwareProfileChange != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_HARDWAREPROFILECHANGE
}
if status.Accepts&AcceptPowerEvent != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_POWEREVENT
}
if status.Accepts&AcceptSessionChange != 0 {
t.ControlsAccepted |= windows.SERVICE_ACCEPT_SESSIONCHANGE
}
if ec.errno == 0 {
t.Win32ExitCode = windows.NO_ERROR
t.ServiceSpecificExitCode = windows.NO_ERROR
} else if ec.isSvcSpecific {
t.Win32ExitCode = uint32(windows.ERROR_SERVICE_SPECIFIC_ERROR)
t.ServiceSpecificExitCode = ec.errno
} else {
t.Win32ExitCode = ec.errno
t.ServiceSpecificExitCode = windows.NO_ERROR
}
t.CheckPoint = status.CheckPoint
t.WaitHint = status.WaitHint
return windows.SetServiceStatus(s.h, &t)
}
const (
sysErrSetServiceStatusFailed = uint32(syscall.APPLICATION_ERROR) + iota
sysErrNewThreadInCallback
)
func (s *service) run() {
s.goWaits.Wait()
s.h = windows.Handle(ssHandle)
argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc]
args := make([]string, len(argv))
for i, a := range argv {
args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:])
}
cmdsToHandler := make(chan ChangeRequest)
changesFromHandler := make(chan Status)
exitFromHandler := make(chan exitCode)
go func() {
ss, errno := s.handler.Execute(args, cmdsToHandler, changesFromHandler)
exitFromHandler <- exitCode{ss, errno}
}()
status := Status{State: Stopped}
ec := exitCode{isSvcSpecific: true, errno: 0}
var outch chan ChangeRequest
inch := s.c
var cmd Cmd
var evtype uint32
var evdata uintptr
loop:
for {
select {
case r := <-inch:
if r.errno != 0 {
ec.errno = r.errno
break loop
}
inch = nil
outch = cmdsToHandler
cmd = r.cmd
evtype = r.eventType
evdata = r.eventData
case outch <- ChangeRequest{cmd, evtype, evdata, status}:
inch = s.c
outch = nil
case c := <-changesFromHandler:
err := s.updateStatus(&c, &ec)
if err != nil {
// best suitable error number
ec.errno = sysErrSetServiceStatusFailed
if err2, ok := err.(syscall.Errno); ok {
ec.errno = uint32(err2)
}
break loop
}
status = c
case ec = <-exitFromHandler:
break loop
}
}
s.updateStatus(&Status{State: Stopped}, &ec)
s.cWaits.Set()
}
func newCallback(fn interface{}) (cb uintptr, err error) {
defer func() {
r := recover()
if r == nil {
return
}
cb = 0
switch v := r.(type) {
case string:
err = errors.New(v)
case error:
err = v
default:
err = errors.New("unexpected panic in syscall.NewCallback")
}
}()
return syscall.NewCallback(fn), nil
}
// BUG(brainman): There is no mechanism to run multiple services
// inside one single executable. Perhaps, it can be overcome by
// using RegisterServiceCtrlHandlerEx Windows api.
// Run executes service name by calling appropriate handler function.
func Run(name string, handler Handler) error {
runtime.LockOSThread()
tid := windows.GetCurrentThreadId()
s, err := newService(name, handler)
if err != nil {
return err
}
ctlHandler := func(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
e := ctlEvent{cmd: Cmd(ctl), eventType: evtype, eventData: evdata}
// We assume that this callback function is running on
// the same thread as Run. Nowhere in MS documentation
// I could find statement to guarantee that. So putting
// check here to verify, otherwise things will go bad
// quickly, if ignored.
i := windows.GetCurrentThreadId()
if i != tid {
e.errno = sysErrNewThreadInCallback
}
s.c <- e
// Always return NO_ERROR (0) for now.
return 0
}
var svcmain uintptr
getServiceMain(&svcmain)
t := []windows.SERVICE_TABLE_ENTRY{
{syscall.StringToUTF16Ptr(s.name), svcmain},
{nil, 0},
}
goWaitsH = uintptr(s.goWaits.h)
cWaitsH = uintptr(s.cWaits.h)
sName = t[0].ServiceName
ctlHandlerExProc, err = newCallback(ctlHandler)
if err != nil {
return err
}
go s.run()
err = windows.StartServiceCtrlDispatcher(&t[0])
if err != nil {
return err
}
return nil
}
// StatusHandle returns service status handle. It is safe to call this function
// from inside the Handler.Execute because then it is guaranteed to be set.
// This code will have to change once multiple services are possible per process.
func StatusHandle() windows.Handle {
return windows.Handle(ssHandle)
}

View File

@ -1,68 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// func servicemain(argc uint32, argv **uint16)
TEXT ·servicemain(SB),7,$0
MOVL argc+0(FP), AX
MOVL AX, ·sArgc(SB)
MOVL argv+4(FP), AX
MOVL AX, ·sArgv(SB)
PUSHL BP
PUSHL BX
PUSHL SI
PUSHL DI
SUBL $12, SP
MOVL ·sName(SB), AX
MOVL AX, (SP)
MOVL $·servicectlhandler(SB), AX
MOVL AX, 4(SP)
MOVL $0, 8(SP)
MOVL ·cRegisterServiceCtrlHandlerExW(SB), AX
MOVL SP, BP
CALL AX
MOVL BP, SP
CMPL AX, $0
JE exit
MOVL AX, ·ssHandle(SB)
MOVL ·goWaitsH(SB), AX
MOVL AX, (SP)
MOVL ·cSetEvent(SB), AX
MOVL SP, BP
CALL AX
MOVL BP, SP
MOVL ·cWaitsH(SB), AX
MOVL AX, (SP)
MOVL $-1, AX
MOVL AX, 4(SP)
MOVL ·cWaitForSingleObject(SB), AX
MOVL SP, BP
CALL AX
MOVL BP, SP
exit:
ADDL $12, SP
POPL DI
POPL SI
POPL BX
POPL BP
MOVL 0(SP), CX
ADDL $12, SP
JMP CX
// I do not know why, but this seems to be the only way to call
// ctlHandlerProc on Windows 7.
// func servicectlhandler(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
TEXT ·servicectlhandler(SB),7,$0
MOVL ·ctlHandlerExProc(SB), CX
JMP CX

View File

@ -1,42 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// func servicemain(argc uint32, argv **uint16)
TEXT ·servicemain(SB),7,$0
MOVL CX, ·sArgc(SB)
MOVL DX, ·sArgv(SB)
SUBQ $32, SP // stack for the first 4 syscall params
MOVQ ·sName(SB), CX
MOVQ $·servicectlhandler(SB), DX
// BUG(pastarmovj): Figure out a way to pass in context in R8.
MOVQ ·cRegisterServiceCtrlHandlerExW(SB), AX
CALL AX
CMPQ AX, $0
JE exit
MOVQ AX, ·ssHandle(SB)
MOVQ ·goWaitsH(SB), CX
MOVQ ·cSetEvent(SB), AX
CALL AX
MOVQ ·cWaitsH(SB), CX
MOVQ $4294967295, DX
MOVQ ·cWaitForSingleObject(SB), AX
CALL AX
exit:
ADDQ $32, SP
RET
// I do not know why, but this seems to be the only way to call
// ctlHandlerProc on Windows 7.
// func ·servicectlhandler(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr {
TEXT ·servicectlhandler(SB),7,$0
MOVQ ·ctlHandlerExProc(SB), AX
JMP AX