Vendor SSPI dependencies.
This commit is contained in:
parent
2a166fd94e
commit
00d40f0bab
2
debian/rules
vendored
2
debian/rules
vendored
@ -17,7 +17,7 @@ endif
|
||||
BUILD_DIR := obj-$(DEB_HOST_GNU_TYPE)
|
||||
export DH_GOPKG := github.com/git-lfs/git-lfs
|
||||
# DH_GOLANG_EXCLUDES typically incorporates vendor exclusions from script/test
|
||||
export DH_GOLANG_EXCLUDES := test github.com/olekukonko/ts/* github.com/xeipuuv/* github.com/spf13/cobra/* github.com/kr/* github.com/pkg/errors
|
||||
export DH_GOLANG_EXCLUDES := test github.com/olekukonko/ts/* github.com/xeipuuv/* github.com/spf13/cobra/* github.com/kr/* github.com/pkg/errors github.com/alexbrainman/sspi/*
|
||||
export PATH := $(CURDIR)/$(BUILD_DIR)/bin:$(PATH)
|
||||
|
||||
# by-default, dh_golang only copies *.go and other source - this upsets a bunch of vendor test routines
|
||||
|
24
glide.lock
generated
24
glide.lock
generated
@ -1,10 +1,18 @@
|
||||
hash: e19b925b9eaca9a10a7742b4a4b1dc8047bff437584538dda59f4f10e69fa6ca
|
||||
updated: 2018-01-29T17:36:52.158516-08:00
|
||||
hash: 61a26ad942b6cdacffd945003b76991b4caeb6a16baab8e86943f6bbc83410e9
|
||||
updated: 2018-02-15T23:41:56.5827516+01:00
|
||||
imports:
|
||||
- name: github.com/alexbrainman/sspi
|
||||
version: 4729b3d4d8581b2db83864d1018926e4154f9406
|
||||
subpackages:
|
||||
- ntlm
|
||||
- name: github.com/bgentry/go-netrc
|
||||
version: 9fd32a8b3d3d3f9d43c341bfe098430e07609480
|
||||
subpackages:
|
||||
- netrc
|
||||
- name: github.com/davecgh/go-spew
|
||||
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
|
||||
subpackages:
|
||||
- spew
|
||||
- name: github.com/inconshreveable/mousetrap
|
||||
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||
- name: github.com/kr/pty
|
||||
@ -13,6 +21,10 @@ imports:
|
||||
version: ecf753e7c962639ab5a1fb46f7da627d4c0a04b8
|
||||
- name: github.com/pkg/errors
|
||||
version: c605e284fe17294bda444b34710735b29d1a9d90
|
||||
- name: github.com/pmezard/go-difflib
|
||||
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
|
||||
subpackages:
|
||||
- difflib
|
||||
- name: github.com/rubyist/tracerx
|
||||
version: 787959303086f44a8c361240dfac53d3e9d53ed2
|
||||
- name: github.com/spf13/cobra
|
||||
@ -32,14 +44,6 @@ imports:
|
||||
- name: github.com/xeipuuv/gojsonschema
|
||||
version: 6b67b3fab74d992bd07f72550006ab2c6907c416
|
||||
testImports:
|
||||
- name: github.com/davecgh/go-spew
|
||||
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
|
||||
subpackages:
|
||||
- spew
|
||||
- name: github.com/pmezard/go-difflib
|
||||
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
|
||||
subpackages:
|
||||
- difflib
|
||||
- name: github.com/xeipuuv/gojsonpointer
|
||||
version: 4e3ac2762d5f479393488629ee9370b50873b3a6
|
||||
- name: github.com/xeipuuv/gojsonreference
|
||||
|
@ -26,3 +26,7 @@ import:
|
||||
version: 6b67b3fab74d992bd07f72550006ab2c6907c416
|
||||
- package: github.com/pkg/errors
|
||||
version: c605e284fe17294bda444b34710735b29d1a9d90
|
||||
- package: github.com/alexbrainman/sspi
|
||||
version: 4729b3d4d8581b2db83864d1018926e4154f9406
|
||||
subpackages:
|
||||
- ntlm
|
@ -16,6 +16,7 @@ if [ $# -eq 0 ]; then
|
||||
| grep -v "github.com/stretchr/testify" \
|
||||
| grep -v "github.com/xeipuuv/gojsonreference" \
|
||||
| grep -v "github.com/xeipuuv/gojsonschema" \
|
||||
| grep -v "github.com/alexbrainman/sspi" \
|
||||
)"
|
||||
else
|
||||
PACKAGES="$(echo "$PACKAGES" \
|
||||
|
27
vendor/github.com/alexbrainman/sspi/LICENSE
generated
vendored
Normal file
27
vendor/github.com/alexbrainman/sspi/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
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.
|
1
vendor/github.com/alexbrainman/sspi/README.md
generated
vendored
Normal file
1
vendor/github.com/alexbrainman/sspi/README.md
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
This repository holds Go packages for accessing Security Support Provider Interface on Windows.
|
57
vendor/github.com/alexbrainman/sspi/buffer.go
generated
vendored
Normal file
57
vendor/github.com/alexbrainman/sspi/buffer.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2015 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 sspi
|
||||
|
||||
import (
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (b *SecBuffer) Set(buftype uint32, data []byte) {
|
||||
b.BufferType = buftype
|
||||
if len(data) > 0 {
|
||||
b.Buffer = &data[0]
|
||||
b.BufferSize = uint32(len(data))
|
||||
} else {
|
||||
b.Buffer = nil
|
||||
b.BufferSize = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SecBuffer) Free() error {
|
||||
if b.Buffer == nil {
|
||||
return nil
|
||||
}
|
||||
return FreeContextBuffer((*byte)(unsafe.Pointer(b.Buffer)))
|
||||
}
|
||||
|
||||
func (b *SecBuffer) Bytes() []byte {
|
||||
if b.Buffer == nil || b.BufferSize <= 0 {
|
||||
return nil
|
||||
}
|
||||
return (*[2 << 20]byte)(unsafe.Pointer(b.Buffer))[:b.BufferSize]
|
||||
}
|
||||
|
||||
func (b *SecBuffer) WriteAll(w io.Writer) (int, error) {
|
||||
if b.BufferSize == 0 || b.Buffer == nil {
|
||||
return 0, nil
|
||||
}
|
||||
data := b.Bytes()
|
||||
total := 0
|
||||
for {
|
||||
n, err := w.Write(data)
|
||||
total += n
|
||||
if err != nil {
|
||||
return total, err
|
||||
}
|
||||
if n >= len(data) {
|
||||
break
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
return total, nil
|
||||
}
|
7
vendor/github.com/alexbrainman/sspi/mksyscall.go
generated
vendored
Normal file
7
vendor/github.com/alexbrainman/sspi/mksyscall.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2018 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 sspi
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=false -output=zsyscall_windows.go syscall.go
|
283
vendor/github.com/alexbrainman/sspi/negotiate/http_test.go
generated
vendored
Normal file
283
vendor/github.com/alexbrainman/sspi/negotiate/http_test.go
generated
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
// Copyright 2016 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 negotiate_test
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alexbrainman/sspi/negotiate"
|
||||
)
|
||||
|
||||
var (
|
||||
testURL = flag.String("url", "", "server URL for TestNegotiateHTTPClient")
|
||||
)
|
||||
|
||||
// TODO: perhaps add Transport that is similar to http.Transport
|
||||
// TODO: perhaps implement separate NTLMTransport and KerberosTransport (not sure about this idea)
|
||||
// TODO: KerberosTransport is (I beleive) sinlge leg protocol, so it can be implemented easily (unlike NTLM)
|
||||
// TODO: perhaps implement both server and client Transport
|
||||
|
||||
type httpClient struct {
|
||||
client *http.Client
|
||||
transport *http.Transport
|
||||
url string
|
||||
}
|
||||
|
||||
func newHTTPClient(url string) *httpClient {
|
||||
transport := &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
}
|
||||
return &httpClient{
|
||||
client: &http.Client{Transport: transport},
|
||||
transport: transport,
|
||||
url: url,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *httpClient) CloseIdleConnections() {
|
||||
c.transport.CloseIdleConnections()
|
||||
}
|
||||
|
||||
func (c *httpClient) get(req *http.Request) (*http.Response, string, error) {
|
||||
res, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return res, string(body), nil
|
||||
}
|
||||
|
||||
func (c *httpClient) canDoNegotiate() error {
|
||||
req, err := http.NewRequest("GET", c.url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res, _, err := c.get(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode != http.StatusUnauthorized {
|
||||
return fmt.Errorf("Unauthorized expected, but got %v", res.StatusCode)
|
||||
}
|
||||
authHeaders, found := res.Header["Www-Authenticate"]
|
||||
if !found {
|
||||
return fmt.Errorf("Www-Authenticate not found")
|
||||
}
|
||||
for _, h := range authHeaders {
|
||||
if h == "Negotiate" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Www-Authenticate header does not contain Negotiate, but has %v", authHeaders)
|
||||
}
|
||||
|
||||
func findAuthHeader(res *http.Response) ([]byte, error) {
|
||||
authHeaders, found := res.Header["Www-Authenticate"]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("Www-Authenticate not found")
|
||||
}
|
||||
if len(authHeaders) != 1 {
|
||||
return nil, fmt.Errorf("Only one Www-Authenticate header expected, but %d found: %v", len(authHeaders), authHeaders)
|
||||
}
|
||||
if len(authHeaders[0]) < 10 {
|
||||
return nil, fmt.Errorf("Www-Authenticate header is to short: %q", authHeaders[0])
|
||||
}
|
||||
if !strings.HasPrefix(authHeaders[0], "Negotiate ") {
|
||||
return nil, fmt.Errorf("Www-Authenticate header is suppose to starts with \"Negotiate \", but is %q", authHeaders[0])
|
||||
}
|
||||
token, err := base64.StdEncoding.DecodeString(authHeaders[0][10:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (c *httpClient) startAuthorization(inputToken []byte) ([]byte, error) {
|
||||
req, err := http.NewRequest("GET", c.url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(inputToken))
|
||||
res, _, err := c.get(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.StatusCode != http.StatusUnauthorized {
|
||||
return nil, fmt.Errorf("Unauthorized expected, but got %v", res.StatusCode)
|
||||
}
|
||||
outputToken, err := findAuthHeader(res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return outputToken, nil
|
||||
}
|
||||
|
||||
func (c *httpClient) completeAuthorization(inputToken []byte) (*http.Response, string, error) {
|
||||
req, err := http.NewRequest("GET", c.url, nil)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "Negotiate "+base64.StdEncoding.EncodeToString(inputToken))
|
||||
res, body, err := c.get(req)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, "", fmt.Errorf("OK expected, but got %v", res.StatusCode)
|
||||
}
|
||||
return res, body, nil
|
||||
}
|
||||
|
||||
func TestNTLMHTTPClient(t *testing.T) {
|
||||
// TODO: combine client and server tests so we don't need external server
|
||||
if len(*testURL) == 0 {
|
||||
t.Skip("Skipping due to empty \"url\" parameter")
|
||||
}
|
||||
|
||||
cred, err := negotiate.AcquireCurrentUserCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cred.Release()
|
||||
|
||||
secctx, clientToken1, err := negotiate.NewClientContext(cred, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer secctx.Release()
|
||||
|
||||
client := newHTTPClient(*testURL)
|
||||
defer client.CloseIdleConnections()
|
||||
|
||||
err = client.canDoNegotiate()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
serverToken1, err := client.startAuthorization(clientToken1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authCompleted, clientToken2, err := secctx.Update(serverToken1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(clientToken2) == 0 {
|
||||
t.Fatal("secctx.Update returns empty token for the peer, but our authentication is not done yet")
|
||||
}
|
||||
res, _, err := client.completeAuthorization(clientToken2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if authCompleted {
|
||||
return
|
||||
}
|
||||
serverToken2, err := findAuthHeader(res)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authCompleted, lastToken, err := secctx.Update(serverToken2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !authCompleted {
|
||||
t.Fatal("client authentication should be completed now")
|
||||
}
|
||||
if len(lastToken) > 0 {
|
||||
t.Fatalf("last token supposed to be empty, but %v returned", lastToken)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKerberosHTTPClient(t *testing.T) {
|
||||
// TODO: combine client and server tests so we don't need external server
|
||||
if len(*testURL) == 0 {
|
||||
t.Skip("Skipping due to empty \"url\" parameter")
|
||||
}
|
||||
|
||||
u, err := url.Parse(*testURL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
targetName := "http/" + strings.ToUpper(u.Host)
|
||||
|
||||
cred, err := negotiate.AcquireCurrentUserCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cred.Release()
|
||||
|
||||
secctx, token, err := negotiate.NewClientContext(cred, targetName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer secctx.Release()
|
||||
|
||||
client := newHTTPClient(*testURL)
|
||||
defer client.CloseIdleConnections()
|
||||
|
||||
err = client.canDoNegotiate()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
res, _, err := client.completeAuthorization(token)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
serverToken, err := findAuthHeader(res)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authCompleted, lastToken, err := secctx.Update(serverToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !authCompleted {
|
||||
t.Fatal("client authentication should be completed now")
|
||||
}
|
||||
if len(lastToken) > 0 {
|
||||
t.Fatalf("last token supposed to be empty, but %v returned", lastToken)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: See http://www.innovation.ch/personal/ronald/ntlm.html#connections about needed to keep connection alive during authentication.
|
||||
|
||||
func TestNegotiateHTTPServer(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO: implement Negotiate authentication here
|
||||
w.Write([]byte("hello"))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
res, err := http.Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(got) != "hello" {
|
||||
t.Errorf("got %q, want hello", string(got))
|
||||
}
|
||||
}
|
348
vendor/github.com/alexbrainman/sspi/negotiate/negotiate.go
generated
vendored
Normal file
348
vendor/github.com/alexbrainman/sspi/negotiate/negotiate.go
generated
vendored
Normal file
@ -0,0 +1,348 @@
|
||||
// Copyright 2016 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 negotiate provides access to the Microsoft Negotiate SSP Package.
|
||||
//
|
||||
package negotiate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/alexbrainman/sspi"
|
||||
)
|
||||
|
||||
// TODO: maybe (if possible) move all winapi related out of sspi and into sspi/internal/winapi
|
||||
|
||||
// PackageInfo contains Negotiate SSP package description.
|
||||
var PackageInfo *sspi.PackageInfo
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
PackageInfo, err = sspi.QueryPackageInfo(sspi.NEGOSSP_NAME)
|
||||
if err != nil {
|
||||
panic("failed to fetch Negotiate package info: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func acquireCredentials(creduse uint32, ai *sspi.SEC_WINNT_AUTH_IDENTITY) (*sspi.Credentials, error) {
|
||||
c, err := sspi.AcquireCredentials(sspi.NEGOSSP_NAME, creduse, (*byte)(unsafe.Pointer(ai)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// AcquireCurrentUserCredentials acquires credentials of currently
|
||||
// logged on user. These will be used by the client to authenticate
|
||||
// itself to the server. It will also be used by the server
|
||||
// to impersonate the user.
|
||||
func AcquireCurrentUserCredentials() (*sspi.Credentials, error) {
|
||||
return acquireCredentials(sspi.SECPKG_CRED_OUTBOUND, nil)
|
||||
}
|
||||
|
||||
// TODO: see if I can share this common ntlm and negotiate code
|
||||
|
||||
// AcquireUserCredentials acquires credentials of user described by
|
||||
// domain, username and password. These will be used by the client to
|
||||
// authenticate itself to the server. It will also be used by the
|
||||
// server to impersonate the user.
|
||||
func AcquireUserCredentials(domain, username, password string) (*sspi.Credentials, error) {
|
||||
if len(domain) == 0 {
|
||||
return nil, errors.New("domain parameter cannot be empty")
|
||||
}
|
||||
if len(username) == 0 {
|
||||
return nil, errors.New("username parameter cannot be empty")
|
||||
}
|
||||
d, err := syscall.UTF16FromString(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u, err := syscall.UTF16FromString(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var p []uint16
|
||||
var plen uint32
|
||||
if len(password) > 0 {
|
||||
p, err = syscall.UTF16FromString(password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plen = uint32(len(p) - 1) // do not count terminating 0
|
||||
}
|
||||
ai := sspi.SEC_WINNT_AUTH_IDENTITY{
|
||||
User: &u[0],
|
||||
UserLength: uint32(len(u) - 1), // do not count terminating 0
|
||||
Domain: &d[0],
|
||||
DomainLength: uint32(len(d) - 1), // do not count terminating 0
|
||||
Password: &p[0],
|
||||
PasswordLength: plen,
|
||||
Flags: sspi.SEC_WINNT_AUTH_IDENTITY_UNICODE,
|
||||
}
|
||||
return acquireCredentials(sspi.SECPKG_CRED_OUTBOUND, &ai)
|
||||
}
|
||||
|
||||
// AcquireServerCredentials acquires server credentials that will
|
||||
// be used to authenticate client.
|
||||
func AcquireServerCredentials() (*sspi.Credentials, error) {
|
||||
return acquireCredentials(sspi.SECPKG_CRED_INBOUND, nil)
|
||||
}
|
||||
|
||||
func updateContext(c *sspi.Context, dst, src []byte, targetName *uint16) (authCompleted bool, n int, err error) {
|
||||
var inBuf, outBuf [1]sspi.SecBuffer
|
||||
inBuf[0].Set(sspi.SECBUFFER_TOKEN, src)
|
||||
inBufs := &sspi.SecBufferDesc{
|
||||
Version: sspi.SECBUFFER_VERSION,
|
||||
BuffersCount: 1,
|
||||
Buffers: &inBuf[0],
|
||||
}
|
||||
outBuf[0].Set(sspi.SECBUFFER_TOKEN, dst)
|
||||
outBufs := &sspi.SecBufferDesc{
|
||||
Version: sspi.SECBUFFER_VERSION,
|
||||
BuffersCount: 1,
|
||||
Buffers: &outBuf[0],
|
||||
}
|
||||
ret := c.Update(targetName, outBufs, inBufs)
|
||||
switch ret {
|
||||
case sspi.SEC_E_OK:
|
||||
// session established -> return success
|
||||
return true, int(outBuf[0].BufferSize), nil
|
||||
case sspi.SEC_I_COMPLETE_NEEDED, sspi.SEC_I_COMPLETE_AND_CONTINUE:
|
||||
ret = sspi.CompleteAuthToken(c.Handle, outBufs)
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return false, 0, ret
|
||||
}
|
||||
case sspi.SEC_I_CONTINUE_NEEDED:
|
||||
default:
|
||||
return false, 0, ret
|
||||
}
|
||||
return false, int(outBuf[0].BufferSize), nil
|
||||
}
|
||||
|
||||
func makeSignature(c *sspi.Context, msg []byte, qop, seqno uint32) ([]byte, error) {
|
||||
_, maxSignature, _, _, err := c.Sizes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if maxSignature == 0 {
|
||||
return nil, errors.New("integrity services are not requested or unavailable")
|
||||
}
|
||||
|
||||
var b [2]sspi.SecBuffer
|
||||
b[0].Set(sspi.SECBUFFER_DATA, msg)
|
||||
b[1].Set(sspi.SECBUFFER_TOKEN, make([]byte, maxSignature))
|
||||
|
||||
ret := sspi.MakeSignature(c.Handle, qop, sspi.NewSecBufferDesc(b[:]), seqno)
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return nil, ret
|
||||
}
|
||||
|
||||
return b[1].Bytes(), nil
|
||||
}
|
||||
|
||||
func verifySignature(c *sspi.Context, msg, token []byte, seqno uint32) (uint32, error) {
|
||||
var b [2]sspi.SecBuffer
|
||||
b[0].Set(sspi.SECBUFFER_DATA, msg)
|
||||
b[1].Set(sspi.SECBUFFER_TOKEN, token)
|
||||
|
||||
var qop uint32
|
||||
|
||||
ret := sspi.VerifySignature(c.Handle, sspi.NewSecBufferDesc(b[:]), seqno, &qop)
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return 0, ret
|
||||
}
|
||||
|
||||
return qop, nil
|
||||
}
|
||||
|
||||
// ClientContext is used by the client to manage all steps of Negotiate negotiation.
|
||||
type ClientContext struct {
|
||||
sctxt *sspi.Context
|
||||
targetName *uint16
|
||||
}
|
||||
|
||||
// NewClientContext creates new client context. It uses client
|
||||
// credentials cred generated by AcquireCurrentUserCredentials or
|
||||
// AcquireUserCredentials and SPN to start client Negotiate
|
||||
// negotiation sequence. targetName is the service principal name
|
||||
// (SPN) or the security context of the destination server.
|
||||
// NewClientContext returns new token to be sent to the server.
|
||||
func NewClientContext(cred *sspi.Credentials, targetName string) (cc *ClientContext, outputToken []byte, err error) {
|
||||
var tname *uint16
|
||||
if len(targetName) > 0 {
|
||||
p, err2 := syscall.UTF16FromString(targetName)
|
||||
if err2 != nil {
|
||||
return nil, nil, err2
|
||||
}
|
||||
if len(p) > 0 {
|
||||
tname = &p[0]
|
||||
}
|
||||
}
|
||||
otoken := make([]byte, PackageInfo.MaxToken)
|
||||
c := sspi.NewClientContext(cred, sspi.ISC_REQ_CONNECTION)
|
||||
authCompleted, n, err2 := updateContext(c, otoken, nil, tname)
|
||||
if err2 != nil {
|
||||
return nil, nil, err2
|
||||
}
|
||||
if authCompleted {
|
||||
c.Release()
|
||||
return nil, nil, errors.New("negotiate authentication should not be completed yet")
|
||||
}
|
||||
if n == 0 {
|
||||
c.Release()
|
||||
return nil, nil, errors.New("negotiate token should not be empty")
|
||||
}
|
||||
otoken = otoken[:n]
|
||||
return &ClientContext{sctxt: c, targetName: tname}, otoken, nil
|
||||
}
|
||||
|
||||
// Release free up resources associated with client context c.
|
||||
func (c *ClientContext) Release() error {
|
||||
return c.sctxt.Release()
|
||||
}
|
||||
|
||||
// Expiry returns c expiry time.
|
||||
func (c *ClientContext) Expiry() time.Time {
|
||||
return c.sctxt.Expiry()
|
||||
}
|
||||
|
||||
// Update advances client part of Negotiate negotiation c. It uses
|
||||
// token received from the server and returns true if client part
|
||||
// of authentication is complete. It also returns new token to be
|
||||
// sent to the server.
|
||||
func (c *ClientContext) Update(token []byte) (authCompleted bool, outputToken []byte, err error) {
|
||||
otoken := make([]byte, PackageInfo.MaxToken)
|
||||
authDone, n, err2 := updateContext(c.sctxt, otoken, token, c.targetName)
|
||||
if err2 != nil {
|
||||
return false, nil, err2
|
||||
}
|
||||
if n == 0 && !authDone {
|
||||
return false, nil, errors.New("negotiate token should not be empty")
|
||||
}
|
||||
otoken = otoken[:n]
|
||||
return authDone, otoken, nil
|
||||
}
|
||||
|
||||
// Sizes queries the client context for the sizes used in per-message
|
||||
// functions. It returns the maximum token size used in authentication
|
||||
// exchanges, the maximum signature size, the preferred integral size of
|
||||
// messages, the size of any security trailer, and any error.
|
||||
func (c *ClientContext) Sizes() (uint32, uint32, uint32, uint32, error) {
|
||||
return c.sctxt.Sizes()
|
||||
}
|
||||
|
||||
// MakeSignature uses the established client context to create a signature
|
||||
// for the given message using the provided quality of protection flags and
|
||||
// sequence number. It returns the signature token in addition to any error.
|
||||
func (c *ClientContext) MakeSignature(msg []byte, qop, seqno uint32) ([]byte, error) {
|
||||
return makeSignature(c.sctxt, msg, qop, seqno)
|
||||
}
|
||||
|
||||
// VerifySignature uses the established client context and signature token
|
||||
// to check that the provided message hasn't been tampered or received out
|
||||
// of sequence. It returns any quality of protection flags and any error
|
||||
// that occurred.
|
||||
func (c *ClientContext) VerifySignature(msg, token []byte, seqno uint32) (uint32, error) {
|
||||
return verifySignature(c.sctxt, msg, token, seqno)
|
||||
}
|
||||
|
||||
// ServerContext is used by the server to manage all steps of Negotiate
|
||||
// negotiation. Once authentication is completed the context can be
|
||||
// used to impersonate client.
|
||||
type ServerContext struct {
|
||||
sctxt *sspi.Context
|
||||
}
|
||||
|
||||
// TODO: I suspect NewServerContext might be the call to complete auth sometimes (see http://blogs.technet.com/b/tristank/archive/2006/08/02/negotiate-this.aspx) - we might need to redesign this call to return authCompleted or similar
|
||||
|
||||
// NewServerContext creates new server context. It uses server
|
||||
// credentials created by AcquireServerCredentials and token from
|
||||
// the client to start server Negotiate negotiation sequence.
|
||||
// It also returns new token to be sent to the client.
|
||||
func NewServerContext(cred *sspi.Credentials, token []byte) (sc *ServerContext, outputToken []byte, err error) {
|
||||
otoken := make([]byte, PackageInfo.MaxToken)
|
||||
c := sspi.NewServerContext(cred, sspi.ASC_REQ_CONNECTION)
|
||||
authDone, n, err2 := updateContext(c, otoken, token, nil)
|
||||
if err2 != nil {
|
||||
return nil, nil, err2
|
||||
}
|
||||
if authDone {
|
||||
c.Release()
|
||||
return nil, nil, errors.New("negotiate authentication should not be completed yet")
|
||||
}
|
||||
if n == 0 {
|
||||
c.Release()
|
||||
return nil, nil, errors.New("negotiate token should not be empty")
|
||||
}
|
||||
otoken = otoken[:n]
|
||||
return &ServerContext{sctxt: c}, otoken, nil
|
||||
}
|
||||
|
||||
// Release free up resources associated with server context c.
|
||||
func (c *ServerContext) Release() error {
|
||||
return c.sctxt.Release()
|
||||
}
|
||||
|
||||
// Expiry returns c expiry time.
|
||||
func (c *ServerContext) Expiry() time.Time {
|
||||
return c.sctxt.Expiry()
|
||||
}
|
||||
|
||||
// Update advances server part of Negotiate negotiation c. It uses
|
||||
// token received from the client and returns true if server part
|
||||
// of authentication is complete. It also returns new token to be
|
||||
// sent to the client.
|
||||
func (c *ServerContext) Update(token []byte) (authCompleted bool, outputToken []byte, err error) {
|
||||
otoken := make([]byte, PackageInfo.MaxToken)
|
||||
authDone, n, err2 := updateContext(c.sctxt, otoken, token, nil)
|
||||
if err2 != nil {
|
||||
return false, nil, err2
|
||||
}
|
||||
if n == 0 && !authDone {
|
||||
return false, nil, errors.New("negotiate token should not be empty")
|
||||
}
|
||||
otoken = otoken[:n]
|
||||
return authDone, otoken, nil
|
||||
}
|
||||
|
||||
// ImpersonateUser changes current OS thread user. New user is
|
||||
// the user as specified by client credentials.
|
||||
func (c *ServerContext) ImpersonateUser() error {
|
||||
return c.sctxt.ImpersonateUser()
|
||||
}
|
||||
|
||||
// RevertToSelf stops impersonation. It changes current OS thread
|
||||
// user to what it was before ImpersonateUser was executed.
|
||||
func (c *ServerContext) RevertToSelf() error {
|
||||
return c.sctxt.RevertToSelf()
|
||||
}
|
||||
|
||||
// Sizes queries the server context for the sizes used in per-message
|
||||
// functions. It returns the maximum token size used in authentication
|
||||
// exchanges, the maximum signature size, the preferred integral size of
|
||||
// messages, the size of any security trailer, and any error.
|
||||
func (c *ServerContext) Sizes() (uint32, uint32, uint32, uint32, error) {
|
||||
return c.sctxt.Sizes()
|
||||
}
|
||||
|
||||
// MakeSignature uses the established server context to create a signature
|
||||
// for the given message using the provided quality of protection flags and
|
||||
// sequence number. It returns the signature token in addition to any error.
|
||||
func (c *ServerContext) MakeSignature(msg []byte, qop, seqno uint32) ([]byte, error) {
|
||||
return makeSignature(c.sctxt, msg, qop, seqno)
|
||||
}
|
||||
|
||||
// VerifySignature uses the established server context and signature token
|
||||
// to check that the provided message hasn't been tampered or received out
|
||||
// of sequence. It returns any quality of protection flags and any error
|
||||
// that occurred.
|
||||
func (c *ServerContext) VerifySignature(msg, token []byte, seqno uint32) (uint32, error) {
|
||||
return verifySignature(c.sctxt, msg, token, seqno)
|
||||
}
|
312
vendor/github.com/alexbrainman/sspi/negotiate/negotiate_test.go
generated
vendored
Normal file
312
vendor/github.com/alexbrainman/sspi/negotiate/negotiate_test.go
generated
vendored
Normal file
@ -0,0 +1,312 @@
|
||||
// Copyright 2016 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 negotiate_test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"flag"
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alexbrainman/sspi"
|
||||
"github.com/alexbrainman/sspi/negotiate"
|
||||
)
|
||||
|
||||
var (
|
||||
testDomain = flag.String("domain", "", "domain parameter for TestAcquireUserCredentials")
|
||||
testUsername = flag.String("username", "", "username parameter for TestAcquireUserCredentials")
|
||||
testPassword = flag.String("password", "", "password parameter for TestAcquireUserCredentials")
|
||||
)
|
||||
|
||||
func TestPackageInfo(t *testing.T) {
|
||||
if negotiate.PackageInfo.Name != "Negotiate" {
|
||||
t.Fatalf(`invalid Negotiate package name of %q, "Negotiate" is expected.`, negotiate.PackageInfo.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func testContextExpiry(t *testing.T, name string, c interface {
|
||||
Expiry() time.Time
|
||||
}) {
|
||||
validFor := c.Expiry().Sub(time.Now())
|
||||
if validFor < time.Hour {
|
||||
t.Errorf("%v expires in %v, more than 1 hour expected", name, validFor)
|
||||
}
|
||||
if validFor > 10*24*time.Hour {
|
||||
t.Errorf("%v expires in %v, less than 10 days expected", name, validFor)
|
||||
}
|
||||
}
|
||||
|
||||
func testNegotiate(t *testing.T, clientCred *sspi.Credentials, SPN string) {
|
||||
if len(SPN) == 0 {
|
||||
t.Log("testing with blank SPN")
|
||||
} else {
|
||||
t.Logf("testing with SPN=%s", SPN)
|
||||
}
|
||||
|
||||
serverCred, err := negotiate.AcquireServerCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer serverCred.Release()
|
||||
|
||||
client, toServerToken, err := negotiate.NewClientContext(clientCred, SPN)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer client.Release()
|
||||
|
||||
if len(toServerToken) == 0 {
|
||||
t.Fatal("token for server cannot be empty")
|
||||
}
|
||||
t.Logf("sent %d bytes to server", len(toServerToken))
|
||||
|
||||
testContextExpiry(t, "client security context", client)
|
||||
|
||||
server, toClientToken, err := negotiate.NewServerContext(serverCred, toServerToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.Release()
|
||||
|
||||
testContextExpiry(t, "server security context", server)
|
||||
|
||||
var clientDone, serverDone bool
|
||||
for {
|
||||
if len(toClientToken) == 0 {
|
||||
break
|
||||
}
|
||||
t.Logf("sent %d bytes to client", len(toClientToken))
|
||||
clientDone, toServerToken, err = client.Update(toClientToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(toServerToken) == 0 {
|
||||
break
|
||||
}
|
||||
t.Logf("sent %d bytes to server", len(toServerToken))
|
||||
serverDone, toClientToken, err = server.Update(toServerToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if !clientDone {
|
||||
t.Fatal("client authentication should be completed now")
|
||||
}
|
||||
if !serverDone {
|
||||
t.Fatal("server authentication should be completed now")
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
err = server.ImpersonateUser()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.RevertToSelf()
|
||||
|
||||
_, err = user.Current()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNegotiate(t *testing.T) {
|
||||
cred, err := negotiate.AcquireCurrentUserCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cred.Release()
|
||||
|
||||
testNegotiate(t, cred, "")
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testNegotiate(t, cred, "HOST/"+strings.ToUpper(hostname))
|
||||
|
||||
testNegotiate(t, cred, "HOST/127.0.0.1")
|
||||
}
|
||||
|
||||
func TestNegotiateFailure(t *testing.T) {
|
||||
clientCred, err := negotiate.AcquireCurrentUserCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer clientCred.Release()
|
||||
|
||||
serverCred, err := negotiate.AcquireServerCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer serverCred.Release()
|
||||
|
||||
client, toServerToken, err := negotiate.NewClientContext(clientCred, "HOST/UNKNOWN_HOST_NAME")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer client.Release()
|
||||
|
||||
if len(toServerToken) == 0 {
|
||||
t.Fatal("token for server cannot be empty")
|
||||
}
|
||||
t.Logf("sent %d bytes to server", len(toServerToken))
|
||||
|
||||
server, toClientToken, err := negotiate.NewServerContext(serverCred, toServerToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.Release()
|
||||
|
||||
for {
|
||||
var clientDone, serverDone bool
|
||||
if len(toClientToken) == 0 {
|
||||
t.Fatal("token for client cannot be empty")
|
||||
}
|
||||
t.Logf("sent %d bytes to client", len(toClientToken))
|
||||
clientDone, toServerToken, err = client.Update(toClientToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("clientDone=%v serverDone=%v", clientDone, serverDone)
|
||||
if clientDone {
|
||||
// t.Fatal("client authentication cannot be completed")
|
||||
}
|
||||
if len(toServerToken) == 0 {
|
||||
t.Fatal("token for server cannot be empty")
|
||||
}
|
||||
t.Logf("sent %d bytes to server", len(toServerToken))
|
||||
serverDone, toClientToken, err = server.Update(toServerToken)
|
||||
if err != nil {
|
||||
if err == sspi.SEC_E_LOGON_DENIED {
|
||||
return
|
||||
}
|
||||
t.Fatalf("unexpected failure 0x%x: %v", uintptr(err.(syscall.Errno)), err)
|
||||
}
|
||||
t.Logf("clientDone=%v serverDone=%v", clientDone, serverDone)
|
||||
if serverDone {
|
||||
t.Fatal("server authentication cannot be completed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcquireUserCredentials(t *testing.T) {
|
||||
if len(*testDomain) == 0 {
|
||||
t.Skip("Skipping due to empty \"domain\" parameter")
|
||||
}
|
||||
if len(*testUsername) == 0 {
|
||||
t.Skip("Skipping due to empty \"username\" parameter")
|
||||
}
|
||||
if len(*testPassword) == 0 {
|
||||
t.Skip("Skipping due to empty \"password\" parameter")
|
||||
}
|
||||
cred, err := negotiate.AcquireUserCredentials(*testDomain, *testUsername, *testPassword)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cred.Release()
|
||||
|
||||
testNegotiate(t, cred, "")
|
||||
}
|
||||
|
||||
func TestSignature(t *testing.T) {
|
||||
clientCred, err := negotiate.AcquireCurrentUserCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer clientCred.Release()
|
||||
|
||||
serverCred, err := negotiate.AcquireServerCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer serverCred.Release()
|
||||
|
||||
client, toServerToken, err := negotiate.NewClientContext(clientCred, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer client.Release()
|
||||
|
||||
if len(toServerToken) == 0 {
|
||||
t.Fatal("token for server cannot be empty")
|
||||
}
|
||||
|
||||
server, toClientToken, err := negotiate.NewServerContext(serverCred, toServerToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.Release()
|
||||
|
||||
var clientDone, serverDone bool
|
||||
for {
|
||||
if len(toClientToken) == 0 {
|
||||
break
|
||||
}
|
||||
clientDone, toServerToken, err = client.Update(toClientToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(toServerToken) == 0 {
|
||||
break
|
||||
}
|
||||
serverDone, toClientToken, err = server.Update(toServerToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if !clientDone {
|
||||
t.Fatal("client authentication should be completed now")
|
||||
}
|
||||
if !serverDone {
|
||||
t.Fatal("server authentication should be completed now")
|
||||
}
|
||||
|
||||
clientMsg := make([]byte, 10)
|
||||
_, err = rand.Read(clientMsg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("clientMsg=%v", clientMsg)
|
||||
|
||||
clientSig, err := client.MakeSignature(clientMsg, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("clientSig=%v", clientSig)
|
||||
|
||||
_, err = server.VerifySignature(clientMsg, clientSig, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("server verified client signature")
|
||||
|
||||
serverMsg := make([]byte, 10)
|
||||
_, err = rand.Read(serverMsg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("serverMsg=%v", serverMsg)
|
||||
|
||||
serverSig, err := server.MakeSignature(serverMsg, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("serverSig=%v", serverSig)
|
||||
|
||||
_, err = client.VerifySignature(serverMsg, serverSig, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("client verified server signature")
|
||||
}
|
177
vendor/github.com/alexbrainman/sspi/ntlm/http_test.go
generated
vendored
Normal file
177
vendor/github.com/alexbrainman/sspi/ntlm/http_test.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
// Copyright 2015 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 ntlm_test
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/alexbrainman/sspi/ntlm"
|
||||
)
|
||||
|
||||
var (
|
||||
testURL = flag.String("url", "", "server URL for TestNTLMHTTPClient")
|
||||
)
|
||||
|
||||
func newRequest() (*http.Request, error) {
|
||||
req, err := http.NewRequest("GET", *testURL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func get(req *http.Request) (*http.Response, string, error) {
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return res, string(body), nil
|
||||
}
|
||||
|
||||
func canDoNTLM() error {
|
||||
req, err := newRequest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res, _, err := get(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode != http.StatusUnauthorized {
|
||||
return fmt.Errorf("Unauthorized expected, but got %v", res.StatusCode)
|
||||
}
|
||||
authHeaders, found := res.Header["Www-Authenticate"]
|
||||
if !found {
|
||||
return fmt.Errorf("Www-Authenticate not found")
|
||||
}
|
||||
for _, h := range authHeaders {
|
||||
if h == "NTLM" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Www-Authenticate header does not contain NTLM, but has %v", authHeaders)
|
||||
}
|
||||
|
||||
func doNTLMNegotiate(negotiate []byte) ([]byte, error) {
|
||||
req, err := newRequest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Authorization", "NTLM "+base64.StdEncoding.EncodeToString(negotiate))
|
||||
res, _, err := get(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res.StatusCode != http.StatusUnauthorized {
|
||||
return nil, fmt.Errorf("Unauthorized expected, but got %v", res.StatusCode)
|
||||
}
|
||||
authHeaders, found := res.Header["Www-Authenticate"]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("Www-Authenticate not found")
|
||||
}
|
||||
if len(authHeaders) != 1 {
|
||||
return nil, fmt.Errorf("Only one Www-Authenticate header expected, but %d found: %v", len(authHeaders), authHeaders)
|
||||
}
|
||||
if len(authHeaders[0]) < 6 {
|
||||
return nil, fmt.Errorf("Www-Authenticate header is to short: %q", authHeaders[0])
|
||||
}
|
||||
if !strings.HasPrefix(authHeaders[0], "NTLM ") {
|
||||
return nil, fmt.Errorf("Www-Authenticate header is suppose to starts with \"NTLM \", but is %q", authHeaders[0])
|
||||
}
|
||||
authenticate, err := base64.StdEncoding.DecodeString(authHeaders[0][5:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return authenticate, nil
|
||||
}
|
||||
|
||||
func doNTLMAuthenticate(authenticate []byte) (string, error) {
|
||||
req, err := newRequest()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "NTLM "+base64.StdEncoding.EncodeToString(authenticate))
|
||||
res, body, err := get(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("OK expected, but got %v", res.StatusCode)
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func TestNTLMHTTPClient(t *testing.T) {
|
||||
// TODO: combine client and server tests so we don't need external server
|
||||
if len(*testURL) == 0 {
|
||||
t.Skip("Skipping due to empty \"url\" parameter")
|
||||
}
|
||||
|
||||
cred, err := ntlm.AcquireCurrentUserCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cred.Release()
|
||||
|
||||
secctx, negotiate, err := ntlm.NewClientContext(cred)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer secctx.Release()
|
||||
|
||||
err = canDoNTLM()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
challenge, err := doNTLMNegotiate(negotiate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authenticate, err := secctx.Update(challenge)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = doNTLMAuthenticate(authenticate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: See http://www.innovation.ch/personal/ronald/ntlm.html#connections about needed to keep connection alive during authentication.
|
||||
|
||||
func TestNTLMHTTPServer(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO: implement NTLM authentication here
|
||||
w.Write([]byte("hello"))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
res, err := http.Get(ts.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(got) != "hello" {
|
||||
t.Errorf("got %q, want hello", string(got))
|
||||
}
|
||||
}
|
265
vendor/github.com/alexbrainman/sspi/ntlm/ntlm.go
generated
vendored
Normal file
265
vendor/github.com/alexbrainman/sspi/ntlm/ntlm.go
generated
vendored
Normal file
@ -0,0 +1,265 @@
|
||||
// Copyright 2015 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 ntlm provides access to the Microsoft NTLM SSP Package.
|
||||
//
|
||||
package ntlm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/alexbrainman/sspi"
|
||||
)
|
||||
|
||||
// PackageInfo contains NTLM SSP package description.
|
||||
var PackageInfo *sspi.PackageInfo
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
PackageInfo, err = sspi.QueryPackageInfo(sspi.NTLMSP_NAME)
|
||||
if err != nil {
|
||||
panic("failed to fetch NTLM package info: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func acquireCredentials(creduse uint32, ai *sspi.SEC_WINNT_AUTH_IDENTITY) (*sspi.Credentials, error) {
|
||||
c, err := sspi.AcquireCredentials(sspi.NTLMSP_NAME, creduse, (*byte)(unsafe.Pointer(ai)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// AcquireCurrentUserCredentials acquires credentials of currently
|
||||
// logged on user. These will be used by the client to authenticate
|
||||
// itself to the server. It will also be used by the server
|
||||
// to impersonate the user.
|
||||
func AcquireCurrentUserCredentials() (*sspi.Credentials, error) {
|
||||
return acquireCredentials(sspi.SECPKG_CRED_OUTBOUND, nil)
|
||||
}
|
||||
|
||||
// AcquireUserCredentials acquires credentials of user described by
|
||||
// domain, username and password. These will be used by the client to
|
||||
// authenticate itself to the server. It will also be used by the
|
||||
// server to impersonate the user.
|
||||
func AcquireUserCredentials(domain, username, password string) (*sspi.Credentials, error) {
|
||||
if len(domain) == 0 {
|
||||
return nil, errors.New("domain parameter cannot be empty")
|
||||
}
|
||||
if len(username) == 0 {
|
||||
return nil, errors.New("username parameter cannot be empty")
|
||||
}
|
||||
d, err := syscall.UTF16FromString(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u, err := syscall.UTF16FromString(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var p []uint16
|
||||
var plen uint32
|
||||
if len(password) > 0 {
|
||||
p, err = syscall.UTF16FromString(password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plen = uint32(len(p) - 1) // do not count terminating 0
|
||||
}
|
||||
ai := sspi.SEC_WINNT_AUTH_IDENTITY{
|
||||
User: &u[0],
|
||||
UserLength: uint32(len(u) - 1), // do not count terminating 0
|
||||
Domain: &d[0],
|
||||
DomainLength: uint32(len(d) - 1), // do not count terminating 0
|
||||
Password: &p[0],
|
||||
PasswordLength: plen,
|
||||
Flags: sspi.SEC_WINNT_AUTH_IDENTITY_UNICODE,
|
||||
}
|
||||
return acquireCredentials(sspi.SECPKG_CRED_OUTBOUND, &ai)
|
||||
}
|
||||
|
||||
// AcquireServerCredentials acquires server credentials that will
|
||||
// be used to authenticate client.
|
||||
func AcquireServerCredentials() (*sspi.Credentials, error) {
|
||||
return acquireCredentials(sspi.SECPKG_CRED_INBOUND, nil)
|
||||
}
|
||||
|
||||
func updateContext(c *sspi.Context, dst, src []byte) (authCompleted bool, n int, err error) {
|
||||
var inBuf, outBuf [1]sspi.SecBuffer
|
||||
inBuf[0].Set(sspi.SECBUFFER_TOKEN, src)
|
||||
inBufs := &sspi.SecBufferDesc{
|
||||
Version: sspi.SECBUFFER_VERSION,
|
||||
BuffersCount: 1,
|
||||
Buffers: &inBuf[0],
|
||||
}
|
||||
outBuf[0].Set(sspi.SECBUFFER_TOKEN, dst)
|
||||
outBufs := &sspi.SecBufferDesc{
|
||||
Version: sspi.SECBUFFER_VERSION,
|
||||
BuffersCount: 1,
|
||||
Buffers: &outBuf[0],
|
||||
}
|
||||
ret := c.Update(nil, outBufs, inBufs)
|
||||
switch ret {
|
||||
case sspi.SEC_E_OK:
|
||||
// session established -> return success
|
||||
return true, int(outBuf[0].BufferSize), nil
|
||||
case sspi.SEC_I_COMPLETE_NEEDED, sspi.SEC_I_COMPLETE_AND_CONTINUE:
|
||||
ret = sspi.CompleteAuthToken(c.Handle, outBufs)
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return false, 0, ret
|
||||
}
|
||||
case sspi.SEC_I_CONTINUE_NEEDED:
|
||||
default:
|
||||
return false, 0, ret
|
||||
}
|
||||
return false, int(outBuf[0].BufferSize), nil
|
||||
}
|
||||
|
||||
// ClientContext is used by the client to manage all steps of NTLM negotiation.
|
||||
type ClientContext struct {
|
||||
sctxt *sspi.Context
|
||||
}
|
||||
|
||||
// NewClientContext creates new client context. It uses client
|
||||
// credentials cred generated by AcquireCurrentUserCredentials or
|
||||
// AcquireUserCredentials and, if successful, outputs negotiate
|
||||
// message. Negotiate message needs to be sent to the server to
|
||||
// start NTLM negotiation sequence.
|
||||
func NewClientContext(cred *sspi.Credentials) (*ClientContext, []byte, error) {
|
||||
negotiate := make([]byte, PackageInfo.MaxToken)
|
||||
c := sspi.NewClientContext(cred, sspi.ISC_REQ_CONNECTION)
|
||||
authCompleted, n, err := updateContext(c, negotiate, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if authCompleted {
|
||||
c.Release()
|
||||
return nil, nil, errors.New("ntlm authentication should not be completed yet")
|
||||
}
|
||||
if n == 0 {
|
||||
c.Release()
|
||||
return nil, nil, errors.New("ntlm token should not be empty")
|
||||
}
|
||||
negotiate = negotiate[:n]
|
||||
return &ClientContext{sctxt: c}, negotiate, nil
|
||||
}
|
||||
|
||||
// Release free up resources associated with client context c.
|
||||
func (c *ClientContext) Release() error {
|
||||
return c.sctxt.Release()
|
||||
}
|
||||
|
||||
// Expiry returns c expiry time.
|
||||
func (c *ClientContext) Expiry() time.Time {
|
||||
return c.sctxt.Expiry()
|
||||
}
|
||||
|
||||
// Update completes client part of NTLM negotiation c. It uses
|
||||
// challenge message received from the server, and generates
|
||||
// authenticate message to be returned to the server.
|
||||
func (c *ClientContext) Update(challenge []byte) ([]byte, error) {
|
||||
authenticate := make([]byte, PackageInfo.MaxToken)
|
||||
authCompleted, n, err := updateContext(c.sctxt, authenticate, challenge)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !authCompleted {
|
||||
return nil, errors.New("ntlm authentication should be completed now")
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, errors.New("ntlm token should not be empty")
|
||||
}
|
||||
authenticate = authenticate[:n]
|
||||
return authenticate, nil
|
||||
}
|
||||
|
||||
// Sizes queries the client context for the sizes used in per-message
|
||||
// functions. It returns the maximum token size used in authentication
|
||||
// exchanges, the maximum signature size, the preferred integral size of
|
||||
// messages, the size of any security trailer, and any error.
|
||||
func (c *ClientContext) Sizes() (uint32, uint32, uint32, uint32, error) {
|
||||
return c.sctxt.Sizes()
|
||||
}
|
||||
|
||||
// ServerContext is used by the server to manage all steps of NTLM
|
||||
// negotiation. Once authentication is completed the context can be
|
||||
// used to impersonate client.
|
||||
type ServerContext struct {
|
||||
sctxt *sspi.Context
|
||||
}
|
||||
|
||||
// NewServerContext creates new server context. It uses server
|
||||
// credentials created by AcquireServerCredentials and client
|
||||
// negotiate message and, if successful, outputs challenge message.
|
||||
// Challenge message needs to be sent to the client to continue
|
||||
// NTLM negotiation sequence.
|
||||
func NewServerContext(cred *sspi.Credentials, negotiate []byte) (*ServerContext, []byte, error) {
|
||||
challenge := make([]byte, PackageInfo.MaxToken)
|
||||
c := sspi.NewServerContext(cred, sspi.ASC_REQ_CONNECTION)
|
||||
authCompleted, n, err := updateContext(c, challenge, negotiate)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if authCompleted {
|
||||
c.Release()
|
||||
return nil, nil, errors.New("ntlm authentication should not be completed yet")
|
||||
}
|
||||
if n == 0 {
|
||||
c.Release()
|
||||
return nil, nil, errors.New("ntlm token should not be empty")
|
||||
}
|
||||
challenge = challenge[:n]
|
||||
return &ServerContext{sctxt: c}, challenge, nil
|
||||
}
|
||||
|
||||
// Release free up resources associated with server context c.
|
||||
func (c *ServerContext) Release() error {
|
||||
return c.sctxt.Release()
|
||||
}
|
||||
|
||||
// Expiry returns c expiry time.
|
||||
func (c *ServerContext) Expiry() time.Time {
|
||||
return c.sctxt.Expiry()
|
||||
}
|
||||
|
||||
// Update completes server part of NTLM negotiation c. It uses
|
||||
// authenticate message received from the client.
|
||||
func (c *ServerContext) Update(authenticate []byte) error {
|
||||
authCompleted, n, err := updateContext(c.sctxt, nil, authenticate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !authCompleted {
|
||||
return errors.New("ntlm authentication should be completed now")
|
||||
}
|
||||
if n != 0 {
|
||||
return errors.New("ntlm token should be empty now")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ImpersonateUser changes current OS thread user. New user is
|
||||
// the user as specified by client credentials.
|
||||
func (c *ServerContext) ImpersonateUser() error {
|
||||
return c.sctxt.ImpersonateUser()
|
||||
}
|
||||
|
||||
// RevertToSelf stops impersonation. It changes current OS thread
|
||||
// user to what it was before ImpersonateUser was executed.
|
||||
func (c *ServerContext) RevertToSelf() error {
|
||||
return c.sctxt.RevertToSelf()
|
||||
}
|
||||
|
||||
// Sizes queries the server context for the sizes used in per-message
|
||||
// functions. It returns the maximum token size used in authentication
|
||||
// exchanges, the maximum signature size, the preferred integral size of
|
||||
// messages, the size of any security trailer, and any error.
|
||||
func (c *ServerContext) Sizes() (uint32, uint32, uint32, uint32, error) {
|
||||
return c.sctxt.Sizes()
|
||||
}
|
119
vendor/github.com/alexbrainman/sspi/ntlm/ntlm_test.go
generated
vendored
Normal file
119
vendor/github.com/alexbrainman/sspi/ntlm/ntlm_test.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright 2015 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 ntlm_test
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alexbrainman/sspi"
|
||||
"github.com/alexbrainman/sspi/ntlm"
|
||||
)
|
||||
|
||||
var (
|
||||
testDomain = flag.String("domain", "", "domain parameter for TestAcquireUserCredentials")
|
||||
testUsername = flag.String("username", "", "username parameter for TestAcquireUserCredentials")
|
||||
testPassword = flag.String("password", "", "password parameter for TestAcquireUserCredentials")
|
||||
)
|
||||
|
||||
func TestPackageInfo(t *testing.T) {
|
||||
if ntlm.PackageInfo.Name != "NTLM" {
|
||||
t.Fatalf(`invalid NTLM package name of %q, "NTLM" is expected.`, ntlm.PackageInfo.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func testContextExpiry(t *testing.T, name string, c interface {
|
||||
Expiry() time.Time
|
||||
}) {
|
||||
validFor := c.Expiry().Sub(time.Now())
|
||||
if validFor < time.Hour {
|
||||
t.Errorf("%v exipries in %v, more then 1 hour expected", name, validFor)
|
||||
}
|
||||
if validFor > 10*24*time.Hour {
|
||||
t.Errorf("%v exipries in %v, less then 10 days expected", name, validFor)
|
||||
}
|
||||
}
|
||||
|
||||
func testNTLM(t *testing.T, clientCred *sspi.Credentials) {
|
||||
serverCred, err := ntlm.AcquireServerCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer serverCred.Release()
|
||||
|
||||
client, token1, err := ntlm.NewClientContext(clientCred)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer client.Release()
|
||||
|
||||
testContextExpiry(t, "clent security context", client)
|
||||
|
||||
server, token2, err := ntlm.NewServerContext(serverCred, token1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.Release()
|
||||
|
||||
testContextExpiry(t, "server security context", server)
|
||||
|
||||
token3, err := client.Update(token2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = server.Update(token3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
err = server.ImpersonateUser()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.RevertToSelf()
|
||||
|
||||
_, err = user.Current()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNTLM(t *testing.T) {
|
||||
cred, err := ntlm.AcquireCurrentUserCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cred.Release()
|
||||
|
||||
testNTLM(t, cred)
|
||||
}
|
||||
|
||||
func TestAcquireUserCredentials(t *testing.T) {
|
||||
if len(*testDomain) == 0 {
|
||||
t.Skip("Skipping due to empty \"domain\" parameter")
|
||||
}
|
||||
if len(*testUsername) == 0 {
|
||||
t.Skip("Skipping due to empty \"username\" parameter")
|
||||
}
|
||||
if len(*testPassword) == 0 {
|
||||
t.Skip("Skipping due to empty \"password\" parameter")
|
||||
}
|
||||
cred, err := ntlm.AcquireUserCredentials(*testDomain, *testUsername, *testPassword)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cred.Release()
|
||||
|
||||
testNTLM(t, cred)
|
||||
}
|
82
vendor/github.com/alexbrainman/sspi/schannel/attribute.go
generated
vendored
Normal file
82
vendor/github.com/alexbrainman/sspi/schannel/attribute.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2015 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 schannel
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/alexbrainman/sspi"
|
||||
)
|
||||
|
||||
// TODO: maybe move all these into a separate package or something
|
||||
|
||||
func (c *Client) streamSizes() (*_SecPkgContext_StreamSizes, error) {
|
||||
// TODO: do not retrive _SecPkgContext_StreamSizes every time (cache the data and invalidate it every time is possible can be changed: handshake, redo, ...)
|
||||
// TODO: maybe return (header, trailer, maxmsg int, err error) instead
|
||||
// TODO: maybe this needs to be exported
|
||||
var ss _SecPkgContext_StreamSizes
|
||||
ret := sspi.QueryContextAttributes(c.ctx.Handle, _SECPKG_ATTR_STREAM_SIZES, (*byte)(unsafe.Pointer(&ss)))
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return nil, ret
|
||||
}
|
||||
return &ss, nil
|
||||
}
|
||||
|
||||
func (c *Client) ProtocolInfo() (name string, major, minor uint32, err error) {
|
||||
var pi _SecPkgContext_ProtoInfo
|
||||
ret := sspi.QueryContextAttributes(c.ctx.Handle, _SECPKG_ATTR_PROTO_INFO, (*byte)(unsafe.Pointer(&pi)))
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return "", 0, 0, ret
|
||||
}
|
||||
defer sspi.FreeContextBuffer((*byte)(unsafe.Pointer(pi.ProtocolName)))
|
||||
s := syscall.UTF16ToString((*[2 << 20]uint16)(unsafe.Pointer(pi.ProtocolName))[:])
|
||||
return s, pi.MajorVersion, pi.MinorVersion, nil
|
||||
}
|
||||
|
||||
func (c *Client) UserName() (string, error) {
|
||||
var ns _SecPkgContext_Names
|
||||
ret := sspi.QueryContextAttributes(c.ctx.Handle, _SECPKG_ATTR_NAMES, (*byte)(unsafe.Pointer(&ns)))
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return "", ret
|
||||
}
|
||||
defer sspi.FreeContextBuffer((*byte)(unsafe.Pointer(ns.UserName)))
|
||||
s := syscall.UTF16ToString((*[2 << 20]uint16)(unsafe.Pointer(ns.UserName))[:])
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (c *Client) AuthorityName() (string, error) {
|
||||
var a _SecPkgContext_Authority
|
||||
ret := sspi.QueryContextAttributes(c.ctx.Handle, _SECPKG_ATTR_AUTHORITY, (*byte)(unsafe.Pointer(&a)))
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return "", ret
|
||||
}
|
||||
defer sspi.FreeContextBuffer((*byte)(unsafe.Pointer(a.AuthorityName)))
|
||||
s := syscall.UTF16ToString((*[2 << 20]uint16)(unsafe.Pointer(a.AuthorityName))[:])
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (c *Client) KeyInfo() (sessionKeySize uint32, sigAlg uint32, sigAlgName string, encAlg uint32, encAlgName string, err error) {
|
||||
var ki _SecPkgContext_KeyInfo
|
||||
ret := sspi.QueryContextAttributes(c.ctx.Handle, _SECPKG_ATTR_KEY_INFO, (*byte)(unsafe.Pointer(&ki)))
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return 0, 0, "", 0, "", ret
|
||||
}
|
||||
defer sspi.FreeContextBuffer((*byte)(unsafe.Pointer(ki.SignatureAlgorithmName)))
|
||||
defer sspi.FreeContextBuffer((*byte)(unsafe.Pointer(ki.EncryptAlgorithmName)))
|
||||
saname := syscall.UTF16ToString((*[2 << 20]uint16)(unsafe.Pointer(ki.SignatureAlgorithmName))[:])
|
||||
eaname := syscall.UTF16ToString((*[2 << 20]uint16)(unsafe.Pointer(ki.EncryptAlgorithmName))[:])
|
||||
return ki.KeySize, ki.SignatureAlgorithm, saname, ki.EncryptAlgorithm, eaname, nil
|
||||
}
|
||||
|
||||
// Sizes queries the context for the sizes used in per-message functions.
|
||||
// It returns the maximum token size used in authentication exchanges, the
|
||||
// maximum signature size, the preferred integral size of messages, the
|
||||
// size of any security trailer, and any error.
|
||||
func (c *Client) Sizes() (uint32, uint32, uint32, uint32, error) {
|
||||
return c.ctx.Sizes()
|
||||
}
|
78
vendor/github.com/alexbrainman/sspi/schannel/buffer.go
generated
vendored
Normal file
78
vendor/github.com/alexbrainman/sspi/schannel/buffer.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2015 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 schannel
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/alexbrainman/sspi"
|
||||
)
|
||||
|
||||
type inputBuffer struct {
|
||||
data []byte
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
func newInputBuffer(initialsize int, reader io.Reader) *inputBuffer {
|
||||
return &inputBuffer{
|
||||
data: make([]byte, 0, initialsize),
|
||||
reader: reader,
|
||||
}
|
||||
}
|
||||
|
||||
// copy copies data d into buffer ib. copy grows destination if needed.
|
||||
func (ib *inputBuffer) copy(d []byte) int {
|
||||
// TODO: check all call sites, maybe this can be made more efficient
|
||||
return copy(ib.data, d)
|
||||
}
|
||||
|
||||
func (ib *inputBuffer) reset() {
|
||||
ib.data = ib.data[:0]
|
||||
}
|
||||
|
||||
func (ib *inputBuffer) grow() {
|
||||
b := make([]byte, len(ib.data), cap(ib.data)*2)
|
||||
copy(b, ib.data)
|
||||
ib.data = b
|
||||
}
|
||||
|
||||
func (ib *inputBuffer) readMore() error {
|
||||
if len(ib.data) == cap(ib.data) {
|
||||
ib.grow()
|
||||
}
|
||||
n0 := len(ib.data)
|
||||
ib.data = ib.data[:cap(ib.data)]
|
||||
n, err := ib.reader.Read(ib.data[n0:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ib.data = ib.data[:n0+n]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ib *inputBuffer) bytes() []byte {
|
||||
return ib.data
|
||||
}
|
||||
|
||||
func sendOutBuffer(w io.Writer, b *sspi.SecBuffer) error {
|
||||
_, err := b.WriteAll(w)
|
||||
// TODO: see if I can preallocate buffers instead
|
||||
b.Free()
|
||||
b.Set(sspi.SECBUFFER_TOKEN, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// indexOfSecBuffer searches buffers bs for buffer type buftype.
|
||||
// It returns -1 if not found.
|
||||
func indexOfSecBuffer(bs []sspi.SecBuffer, buftype uint32) int {
|
||||
for i := range bs {
|
||||
if bs[i].BufferType == buftype {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
276
vendor/github.com/alexbrainman/sspi/schannel/client.go
generated
vendored
Normal file
276
vendor/github.com/alexbrainman/sspi/schannel/client.go
generated
vendored
Normal file
@ -0,0 +1,276 @@
|
||||
// Copyright 2015 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 schannel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/alexbrainman/sspi"
|
||||
)
|
||||
|
||||
// TODO: add documentation
|
||||
|
||||
// TODO: maybe come up with a better name
|
||||
|
||||
type Client struct {
|
||||
ctx *sspi.Context
|
||||
conn io.ReadWriter
|
||||
inbuf *inputBuffer
|
||||
}
|
||||
|
||||
func NewClientContext(cred *sspi.Credentials, conn io.ReadWriter) *Client {
|
||||
return &Client{
|
||||
ctx: sspi.NewClientContext(cred, sspi.ISC_REQ_STREAM|sspi.ISC_REQ_ALLOCATE_MEMORY|sspi.ISC_REQ_EXTENDED_ERROR|sspi.ISC_REQ_MANUAL_CRED_VALIDATION),
|
||||
conn: conn,
|
||||
// TODO: decide how large this buffer needs to be (it cannot be too small otherwise messages won't fit)
|
||||
inbuf: newInputBuffer(1000, conn),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Handshake(serverName string) error {
|
||||
name, err := syscall.UTF16PtrFromString(serverName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
inBuf := []sspi.SecBuffer{
|
||||
{BufferType: sspi.SECBUFFER_TOKEN},
|
||||
{BufferType: sspi.SECBUFFER_EMPTY},
|
||||
}
|
||||
// TODO: InitializeSecurityContext doco says that inBufs should be nil on the first call
|
||||
inBufs := sspi.NewSecBufferDesc(inBuf[:])
|
||||
outBuf := []sspi.SecBuffer{
|
||||
{BufferType: sspi.SECBUFFER_TOKEN},
|
||||
}
|
||||
outBufs := sspi.NewSecBufferDesc(outBuf)
|
||||
|
||||
for {
|
||||
ret := c.ctx.Update(name, outBufs, inBufs)
|
||||
|
||||
// send data to peer
|
||||
err := sendOutBuffer(c.conn, &outBuf[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update input buffer
|
||||
fetchMore := true
|
||||
switch ret {
|
||||
case sspi.SEC_E_OK, sspi.SEC_I_CONTINUE_NEEDED:
|
||||
if inBuf[1].BufferType == sspi.SECBUFFER_EXTRA {
|
||||
c.inbuf.copy(inBuf[1].Bytes())
|
||||
fetchMore = false
|
||||
} else {
|
||||
c.inbuf.reset()
|
||||
}
|
||||
}
|
||||
|
||||
// decide what to do next
|
||||
switch ret {
|
||||
case sspi.SEC_E_OK:
|
||||
// negotiation is competed
|
||||
return nil
|
||||
case sspi.SEC_I_CONTINUE_NEEDED, sspi.SEC_E_INCOMPLETE_MESSAGE:
|
||||
// continue on
|
||||
default:
|
||||
return ret
|
||||
}
|
||||
|
||||
// fetch more input data if needed
|
||||
if fetchMore {
|
||||
err := c.inbuf.readMore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
inBuf[0].Set(sspi.SECBUFFER_TOKEN, c.inbuf.bytes())
|
||||
inBuf[1].Set(sspi.SECBUFFER_EMPTY, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: protect Handshake, Read, Write and Shutdown with locks
|
||||
// TODO: call Handshake at the start Read and Write unless handshake is already complete
|
||||
|
||||
func (c *Client) writeBlock(data []byte) (int, error) {
|
||||
ss, err := c.streamSizes()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// TODO: maybe make this buffer (and header and trailer buffers) part of Context struct
|
||||
var b [4]sspi.SecBuffer
|
||||
b[0].Set(sspi.SECBUFFER_STREAM_HEADER, make([]byte, ss.Header))
|
||||
b[1].Set(sspi.SECBUFFER_DATA, data)
|
||||
b[2].Set(sspi.SECBUFFER_STREAM_TRAILER, make([]byte, ss.Trailer))
|
||||
b[3].Set(sspi.SECBUFFER_EMPTY, nil)
|
||||
ret := sspi.EncryptMessage(c.ctx.Handle, 0, sspi.NewSecBufferDesc(b[:]), 0)
|
||||
switch ret {
|
||||
case sspi.SEC_E_OK:
|
||||
case sspi.SEC_E_CONTEXT_EXPIRED:
|
||||
// TODO: handle this
|
||||
panic("writeBlock: SEC_E_CONTEXT_EXPIRED")
|
||||
default:
|
||||
return 0, ret
|
||||
}
|
||||
n1, err := b[0].WriteAll(c.conn)
|
||||
if err != nil {
|
||||
return n1, err
|
||||
}
|
||||
n2, err := b[1].WriteAll(c.conn)
|
||||
if err != nil {
|
||||
return n1 + n2, err
|
||||
}
|
||||
n3, err := b[2].WriteAll(c.conn)
|
||||
return n1 + n2 + n3, err
|
||||
}
|
||||
|
||||
func (c *Client) Write(b []byte) (int, error) {
|
||||
ss, err := c.streamSizes()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// TODO: handle redoing context here
|
||||
total := 0
|
||||
for len(b) > 0 {
|
||||
// TODO: maybe use ss.BlockSize to decide on optimum block size
|
||||
b2 := b
|
||||
if len(b) > int(ss.MaximumMessage) {
|
||||
b2 = b2[:ss.MaximumMessage]
|
||||
}
|
||||
n, err := c.writeBlock(b2)
|
||||
total += n
|
||||
if err != nil {
|
||||
return total, err
|
||||
}
|
||||
b = b[len(b2):]
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
func (c *Client) Read(data []byte) (int, error) {
|
||||
if len(c.inbuf.bytes()) == 0 {
|
||||
err := c.inbuf.readMore()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
var b [4]sspi.SecBuffer
|
||||
desc := sspi.NewSecBufferDesc(b[:])
|
||||
loop:
|
||||
for {
|
||||
b[0].Set(sspi.SECBUFFER_DATA, c.inbuf.bytes())
|
||||
b[1].Set(sspi.SECBUFFER_EMPTY, nil)
|
||||
b[2].Set(sspi.SECBUFFER_EMPTY, nil)
|
||||
b[3].Set(sspi.SECBUFFER_EMPTY, nil)
|
||||
ret := sspi.DecryptMessage(c.ctx.Handle, desc, 0, nil)
|
||||
switch ret {
|
||||
case sspi.SEC_E_OK:
|
||||
break loop
|
||||
case sspi.SEC_E_INCOMPLETE_MESSAGE:
|
||||
// TODO: it seems b[0].BufferSize or b[1].BufferSize contains "how many more bytes needed for full message" - maybe use it somehow
|
||||
// read more and try again
|
||||
err := c.inbuf.readMore()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
default:
|
||||
// TODO: handle other ret values
|
||||
return 0, errors.New("not implemented")
|
||||
}
|
||||
}
|
||||
i := indexOfSecBuffer(b[:], sspi.SECBUFFER_DATA)
|
||||
if i == -1 {
|
||||
return 0, errors.New("DecryptMessage did not return SECBUFFER_DATA")
|
||||
}
|
||||
n := copy(data, b[i].Bytes())
|
||||
i = indexOfSecBuffer(b[:], sspi.SECBUFFER_EXTRA)
|
||||
if i == -1 {
|
||||
c.inbuf.reset()
|
||||
} else {
|
||||
c.inbuf.copy(b[i].Bytes())
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (c *Client) applyShutdownControlToken() error {
|
||||
data := uint32(_SCHANNEL_SHUTDOWN)
|
||||
b := sspi.SecBuffer{
|
||||
BufferType: sspi.SECBUFFER_TOKEN,
|
||||
Buffer: (*byte)(unsafe.Pointer(&data)),
|
||||
BufferSize: uint32(unsafe.Sizeof(data)),
|
||||
}
|
||||
desc := sspi.SecBufferDesc{
|
||||
Version: sspi.SECBUFFER_VERSION,
|
||||
BuffersCount: 1,
|
||||
Buffers: &b,
|
||||
}
|
||||
ret := sspi.ApplyControlToken(c.ctx.Handle, &desc)
|
||||
if ret != sspi.SEC_E_OK {
|
||||
return ret
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Shutdown() error {
|
||||
err := c.applyShutdownControlToken()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
inBuf := []sspi.SecBuffer{
|
||||
{BufferType: sspi.SECBUFFER_TOKEN},
|
||||
{BufferType: sspi.SECBUFFER_EMPTY},
|
||||
}
|
||||
inBufs := sspi.NewSecBufferDesc(inBuf[:])
|
||||
outBuf := []sspi.SecBuffer{
|
||||
{BufferType: sspi.SECBUFFER_TOKEN},
|
||||
}
|
||||
outBufs := sspi.NewSecBufferDesc(outBuf)
|
||||
for {
|
||||
// TODO: I am not sure if I can pass nil as targname
|
||||
ret := c.ctx.Update(nil, outBufs, inBufs)
|
||||
|
||||
// send data to peer
|
||||
err := sendOutBuffer(c.conn, &outBuf[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update input buffer
|
||||
fetchMore := true
|
||||
switch ret {
|
||||
case sspi.SEC_E_OK, sspi.SEC_I_CONTINUE_NEEDED:
|
||||
if inBuf[1].BufferType == sspi.SECBUFFER_EXTRA {
|
||||
c.inbuf.copy(inBuf[1].Bytes())
|
||||
fetchMore = false
|
||||
} else {
|
||||
c.inbuf.reset()
|
||||
}
|
||||
}
|
||||
|
||||
// decide what to do next
|
||||
switch ret {
|
||||
case sspi.SEC_E_OK, sspi.SEC_E_CONTEXT_EXPIRED:
|
||||
// shutdown is competed
|
||||
return nil
|
||||
case sspi.SEC_I_CONTINUE_NEEDED, sspi.SEC_E_INCOMPLETE_MESSAGE:
|
||||
// continue on
|
||||
default:
|
||||
return ret
|
||||
}
|
||||
|
||||
// fetch more input data if needed
|
||||
if fetchMore {
|
||||
err := c.inbuf.readMore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
inBuf[0].Set(sspi.SECBUFFER_TOKEN, c.inbuf.bytes())
|
||||
inBuf[1].Set(sspi.SECBUFFER_EMPTY, nil)
|
||||
}
|
||||
}
|
47
vendor/github.com/alexbrainman/sspi/schannel/creds.go
generated
vendored
Normal file
47
vendor/github.com/alexbrainman/sspi/schannel/creds.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2015 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 schannel provides access to the Secure Channel SSP Package.
|
||||
//
|
||||
package schannel
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/alexbrainman/sspi"
|
||||
)
|
||||
|
||||
// TODO: add documentation
|
||||
|
||||
// PackageInfo contains Secure Channel SSP package description.
|
||||
var PackageInfo *sspi.PackageInfo
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
PackageInfo, err = sspi.QueryPackageInfo(sspi.UNISP_NAME)
|
||||
if err != nil {
|
||||
panic("failed to fetch Schannel package info: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func acquireCredentials(creduse uint32) (*sspi.Credentials, error) {
|
||||
sc := &__SCHANNEL_CRED{
|
||||
Version: __SCHANNEL_CRED_VERSION,
|
||||
// TODO: allow for Creds / CredCount
|
||||
// TODO: allow for RootStore
|
||||
// TODO: allow for EnabledProtocols
|
||||
// TODO: allow for MinimumCipherStrength / MaximumCipherStrength
|
||||
}
|
||||
c, err := sspi.AcquireCredentials(sspi.UNISP_NAME, creduse, (*byte)(unsafe.Pointer(sc)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func AcquireClientCredentials() (*sspi.Credentials, error) {
|
||||
return acquireCredentials(sspi.SECPKG_CRED_OUTBOUND)
|
||||
}
|
77
vendor/github.com/alexbrainman/sspi/schannel/schannel_test.go
generated
vendored
Normal file
77
vendor/github.com/alexbrainman/sspi/schannel/schannel_test.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2015 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 schannel_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/alexbrainman/sspi/schannel"
|
||||
)
|
||||
|
||||
func TestPackageInfo(t *testing.T) {
|
||||
want := "Microsoft Unified Security Protocol Provider"
|
||||
if schannel.PackageInfo.Name != want {
|
||||
t.Fatalf(`invalid Schannel package name of %q, %q is expected.`, schannel.PackageInfo.Name, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSchannel(t *testing.T) {
|
||||
cred, err := schannel.AcquireClientCredentials()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cred.Release()
|
||||
|
||||
conn, err := net.Dial("tcp", "microsoft.com:https")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := schannel.NewClientContext(cred, conn)
|
||||
err = client.Handshake("microsoft.com")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
protoName, major, minor, err := client.ProtocolInfo()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("protocol info: %s %d.%d", protoName, major, minor)
|
||||
userName, err := client.UserName()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("user name: %q", userName)
|
||||
authorityName, err := client.AuthorityName()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("authority name: %q", authorityName)
|
||||
sessionKeySize, sigAlg, sigAlgName, encAlg, encAlgName, err := client.KeyInfo()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("key info: session_key_size=%d signature_alg=%q(%d) encryption_alg=%q(%d)", sessionKeySize, sigAlgName, sigAlg, encAlgName, encAlg)
|
||||
// TODO: add some code to verify if negotiated connection is suitable (ciper and so on)
|
||||
_, err = fmt.Fprintf(client, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data, err := ioutil.ReadAll(client)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("web page: %q", data)
|
||||
err = client.Shutdown()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
109
vendor/github.com/alexbrainman/sspi/schannel/syscall.go
generated
vendored
Normal file
109
vendor/github.com/alexbrainman/sspi/schannel/syscall.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright 2015 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 schannel
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// TODO: maybe put all these into a separate package, like sspi/schannel/winapi or similar
|
||||
|
||||
const (
|
||||
__SCHANNEL_CRED_VERSION = 4
|
||||
|
||||
_SP_PROT_PCT1_SERVER = 0x00000001
|
||||
_SP_PROT_PCT1_CLIENT = 0x00000002
|
||||
_SP_PROT_PCT1 = _SP_PROT_PCT1_SERVER | _SP_PROT_PCT1_CLIENT
|
||||
_SP_PROT_SSL2_SERVER = 0x00000004
|
||||
_SP_PROT_SSL2_CLIENT = 0x00000008
|
||||
_SP_PROT_SSL2 = _SP_PROT_SSL2_SERVER | _SP_PROT_SSL2_CLIENT
|
||||
_SP_PROT_SSL3_SERVER = 0x00000010
|
||||
_SP_PROT_SSL3_CLIENT = 0x00000020
|
||||
_SP_PROT_SSL3 = _SP_PROT_SSL3_SERVER | _SP_PROT_SSL3_CLIENT
|
||||
_SP_PROT_TLS1_SERVER = 0x00000040
|
||||
_SP_PROT_TLS1_CLIENT = 0x00000080
|
||||
_SP_PROT_TLS1 = _SP_PROT_TLS1_SERVER | _SP_PROT_TLS1_CLIENT
|
||||
_SP_PROT_SSL3TLS1_CLIENTS = _SP_PROT_TLS1_CLIENT | _SP_PROT_SSL3_CLIENT
|
||||
_SP_PROT_SSL3TLS1_SERVERS = _SP_PROT_TLS1_SERVER | _SP_PROT_SSL3_SERVER
|
||||
_SP_PROT_SSL3TLS1 = _SP_PROT_SSL3 | _SP_PROT_TLS1
|
||||
)
|
||||
|
||||
type __SCHANNEL_CRED struct {
|
||||
Version uint32
|
||||
CredCount uint32
|
||||
Creds *syscall.CertContext
|
||||
RootStore syscall.Handle // TODO: make sure this field is syscall.Handle
|
||||
cMappers uint32
|
||||
aphMappers uintptr
|
||||
SupportedAlgCount uint32
|
||||
SupportedAlgs *uint32
|
||||
EnabledProtocols uint32
|
||||
MinimumCipherStrength uint32
|
||||
MaximumCipherStrength uint32
|
||||
SessionLifespan uint32
|
||||
Flags uint32
|
||||
CredFormat uint32
|
||||
}
|
||||
|
||||
const (
|
||||
_SECPKG_ATTR_SIZES = 0
|
||||
_SECPKG_ATTR_NAMES = 1
|
||||
_SECPKG_ATTR_LIFESPAN = 2
|
||||
_SECPKG_ATTR_DCE_INFO = 3
|
||||
_SECPKG_ATTR_STREAM_SIZES = 4
|
||||
_SECPKG_ATTR_KEY_INFO = 5
|
||||
_SECPKG_ATTR_AUTHORITY = 6
|
||||
_SECPKG_ATTR_PROTO_INFO = 7
|
||||
_SECPKG_ATTR_PASSWORD_EXPIRY = 8
|
||||
_SECPKG_ATTR_SESSION_KEY = 9
|
||||
_SECPKG_ATTR_PACKAGE_INFO = 10
|
||||
_SECPKG_ATTR_USER_FLAGS = 11
|
||||
_SECPKG_ATTR_NEGOTIATION_INFO = 12
|
||||
_SECPKG_ATTR_NATIVE_NAMES = 13
|
||||
_SECPKG_ATTR_FLAGS = 14
|
||||
|
||||
_SCHANNEL_RENEGOTIATE = 0
|
||||
_SCHANNEL_SHUTDOWN = 1
|
||||
_SCHANNEL_ALERT = 2
|
||||
)
|
||||
|
||||
type _SecPkgContext_StreamSizes struct {
|
||||
Header uint32
|
||||
Trailer uint32
|
||||
MaximumMessage uint32
|
||||
Buffers uint32
|
||||
BlockSize uint32
|
||||
}
|
||||
|
||||
type _SecPkgContext_ProtoInfo struct {
|
||||
ProtocolName *uint16
|
||||
MajorVersion uint32
|
||||
MinorVersion uint32
|
||||
}
|
||||
|
||||
type _SecPkgContext_Names struct {
|
||||
UserName *uint16
|
||||
}
|
||||
|
||||
type _SecPkgContext_Authority struct {
|
||||
AuthorityName *uint16
|
||||
}
|
||||
|
||||
type _SecPkgContext_KeyInfo struct {
|
||||
SignatureAlgorithmName *uint16
|
||||
EncryptAlgorithmName *uint16
|
||||
KeySize uint32
|
||||
SignatureAlgorithm uint32
|
||||
EncryptAlgorithm uint32
|
||||
}
|
||||
|
||||
// TODO: SecPkgContext_ConnectionInfo
|
||||
|
||||
// TODO: SECPKG_ATTR_REMOTE_CERT_CONTEXT
|
||||
// TODO: SECPKG_ATTR_LOCAL_CERT_CONTEXT
|
||||
|
||||
// TODO: SecPkgContext_IssuerListInfoEx
|
177
vendor/github.com/alexbrainman/sspi/sspi.go
generated
vendored
Normal file
177
vendor/github.com/alexbrainman/sspi/sspi.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
// Copyright 2015 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 sspi
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// TODO: add documentation
|
||||
|
||||
type PackageInfo struct {
|
||||
Capabilities uint32
|
||||
Version uint16
|
||||
RPCID uint16
|
||||
MaxToken uint32
|
||||
Name string
|
||||
Comment string
|
||||
}
|
||||
|
||||
func QueryPackageInfo(pkgname string) (*PackageInfo, error) {
|
||||
name, err := syscall.UTF16PtrFromString(pkgname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pi *SecPkgInfo
|
||||
ret := QuerySecurityPackageInfo(name, &pi)
|
||||
if ret != SEC_E_OK {
|
||||
return nil, ret
|
||||
}
|
||||
defer FreeContextBuffer((*byte)(unsafe.Pointer(pi)))
|
||||
|
||||
return &PackageInfo{
|
||||
Capabilities: pi.Capabilities,
|
||||
Version: pi.Version,
|
||||
RPCID: pi.RPCID,
|
||||
MaxToken: pi.MaxToken,
|
||||
Name: syscall.UTF16ToString((*[2 << 12]uint16)(unsafe.Pointer(pi.Name))[:]),
|
||||
Comment: syscall.UTF16ToString((*[2 << 12]uint16)(unsafe.Pointer(pi.Comment))[:]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Credentials struct {
|
||||
Handle CredHandle
|
||||
expiry syscall.Filetime
|
||||
}
|
||||
|
||||
func AcquireCredentials(pkgname string, creduse uint32, authdata *byte) (*Credentials, error) {
|
||||
name, err := syscall.UTF16PtrFromString(pkgname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var c Credentials
|
||||
ret := AcquireCredentialsHandle(nil, name, creduse, nil, authdata, 0, 0, &c.Handle, &c.expiry)
|
||||
if ret != SEC_E_OK {
|
||||
return nil, ret
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func (c *Credentials) Release() error {
|
||||
ret := FreeCredentialsHandle(&c.Handle)
|
||||
if ret != SEC_E_OK {
|
||||
return ret
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Credentials) Expiry() time.Time {
|
||||
return time.Unix(0, c.expiry.Nanoseconds())
|
||||
}
|
||||
|
||||
// TODO: add functions to display and manage RequestedFlags and EstablishedFlags fields.
|
||||
// TODO: maybe get rid of RequestedFlags and EstablishedFlags fields, and replace them with input parameter for New...Context and return value of Update (instead of current bool parameter).
|
||||
|
||||
type updateFunc func(c *Context, targname *uint16, h, newh *CtxtHandle, out, in *SecBufferDesc) syscall.Errno
|
||||
|
||||
type Context struct {
|
||||
Cred *Credentials
|
||||
Handle *CtxtHandle
|
||||
handle CtxtHandle
|
||||
updFn updateFunc
|
||||
expiry syscall.Filetime
|
||||
RequestedFlags uint32
|
||||
EstablishedFlags uint32
|
||||
}
|
||||
|
||||
func NewClientContext(cred *Credentials, flags uint32) *Context {
|
||||
return &Context{
|
||||
Cred: cred,
|
||||
updFn: initialize,
|
||||
RequestedFlags: flags,
|
||||
}
|
||||
}
|
||||
|
||||
func NewServerContext(cred *Credentials, flags uint32) *Context {
|
||||
return &Context{
|
||||
Cred: cred,
|
||||
updFn: accept,
|
||||
RequestedFlags: flags,
|
||||
}
|
||||
}
|
||||
|
||||
func initialize(c *Context, targname *uint16, h, newh *CtxtHandle, out, in *SecBufferDesc) syscall.Errno {
|
||||
return InitializeSecurityContext(&c.Cred.Handle, h, targname, c.RequestedFlags,
|
||||
0, SECURITY_NATIVE_DREP, in, 0, newh, out, &c.EstablishedFlags, &c.expiry)
|
||||
}
|
||||
|
||||
func accept(c *Context, targname *uint16, h, newh *CtxtHandle, out, in *SecBufferDesc) syscall.Errno {
|
||||
return AcceptSecurityContext(&c.Cred.Handle, h, in, c.RequestedFlags,
|
||||
SECURITY_NATIVE_DREP, newh, out, &c.EstablishedFlags, &c.expiry)
|
||||
}
|
||||
|
||||
func (c *Context) Update(targname *uint16, out, in *SecBufferDesc) syscall.Errno {
|
||||
h := c.Handle
|
||||
if c.Handle == nil {
|
||||
c.Handle = &c.handle
|
||||
}
|
||||
return c.updFn(c, targname, h, c.Handle, out, in)
|
||||
}
|
||||
|
||||
func (c *Context) Release() error {
|
||||
ret := DeleteSecurityContext(c.Handle)
|
||||
if ret != SEC_E_OK {
|
||||
return ret
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Context) Expiry() time.Time {
|
||||
return time.Unix(0, c.expiry.Nanoseconds())
|
||||
}
|
||||
|
||||
// TODO: add comment to function doco that this "impersonation" is applied to current OS thread.
|
||||
func (c *Context) ImpersonateUser() error {
|
||||
ret := ImpersonateSecurityContext(c.Handle)
|
||||
if ret != SEC_E_OK {
|
||||
return ret
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Context) RevertToSelf() error {
|
||||
ret := RevertSecurityContext(c.Handle)
|
||||
if ret != SEC_E_OK {
|
||||
return ret
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sizes queries the context for the sizes used in per-message functions.
|
||||
// It returns the maximum token size used in authentication exchanges, the
|
||||
// maximum signature size, the preferred integral size of messages, the
|
||||
// size of any security trailer, and any error.
|
||||
func (c *Context) Sizes() (uint32, uint32, uint32, uint32, error) {
|
||||
var s _SecPkgContext_Sizes
|
||||
ret := QueryContextAttributes(c.Handle, _SECPKG_ATTR_SIZES, (*byte)(unsafe.Pointer(&s)))
|
||||
if ret != SEC_E_OK {
|
||||
return 0, 0, 0, 0, ret
|
||||
}
|
||||
return s.MaxToken, s.MaxSignature, s.BlockSize, s.SecurityTrailer, nil
|
||||
}
|
||||
|
||||
// NewSecBufferDesc returns an initialized SecBufferDesc describing the
|
||||
// provided SecBuffer.
|
||||
func NewSecBufferDesc(b []SecBuffer) *SecBufferDesc {
|
||||
return &SecBufferDesc{
|
||||
Version: SECBUFFER_VERSION,
|
||||
BuffersCount: uint32(len(b)),
|
||||
Buffers: &b[0],
|
||||
}
|
||||
}
|
33
vendor/github.com/alexbrainman/sspi/sspi_test.go
generated
vendored
Normal file
33
vendor/github.com/alexbrainman/sspi/sspi_test.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2015 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 sspi_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/alexbrainman/sspi"
|
||||
)
|
||||
|
||||
func TestQueryPackageInfo(t *testing.T) {
|
||||
pkgnames := []string{
|
||||
sspi.NTLMSP_NAME,
|
||||
sspi.MICROSOFT_KERBEROS_NAME,
|
||||
sspi.NEGOSSP_NAME,
|
||||
sspi.UNISP_NAME,
|
||||
}
|
||||
for _, name := range pkgnames {
|
||||
pi, err := sspi.QueryPackageInfo(name)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
if pi.Name != name {
|
||||
t.Errorf("unexpected package name %q returned for %q package: package info is %#v", pi.Name, name, pi)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
174
vendor/github.com/alexbrainman/sspi/syscall.go
generated
vendored
Normal file
174
vendor/github.com/alexbrainman/sspi/syscall.go
generated
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
// Copyright 2015 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 sspi
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
SEC_E_OK = syscall.Errno(0)
|
||||
|
||||
SEC_I_COMPLETE_AND_CONTINUE = syscall.Errno(590612)
|
||||
SEC_I_COMPLETE_NEEDED = syscall.Errno(590611)
|
||||
SEC_I_CONTINUE_NEEDED = syscall.Errno(590610)
|
||||
|
||||
SEC_E_LOGON_DENIED = syscall.Errno(0x8009030c)
|
||||
SEC_E_CONTEXT_EXPIRED = syscall.Errno(0x80090317) // not sure if the value is valid
|
||||
SEC_E_INCOMPLETE_MESSAGE = syscall.Errno(0x80090318)
|
||||
|
||||
NTLMSP_NAME = "NTLM"
|
||||
MICROSOFT_KERBEROS_NAME = "Kerberos"
|
||||
NEGOSSP_NAME = "Negotiate"
|
||||
UNISP_NAME = "Microsoft Unified Security Protocol Provider"
|
||||
|
||||
_SECPKG_ATTR_SIZES = 0
|
||||
_SECPKG_ATTR_NAMES = 1
|
||||
_SECPKG_ATTR_LIFESPAN = 2
|
||||
_SECPKG_ATTR_DCE_INFO = 3
|
||||
_SECPKG_ATTR_STREAM_SIZES = 4
|
||||
_SECPKG_ATTR_KEY_INFO = 5
|
||||
_SECPKG_ATTR_AUTHORITY = 6
|
||||
_SECPKG_ATTR_PROTO_INFO = 7
|
||||
_SECPKG_ATTR_PASSWORD_EXPIRY = 8
|
||||
_SECPKG_ATTR_SESSION_KEY = 9
|
||||
_SECPKG_ATTR_PACKAGE_INFO = 10
|
||||
_SECPKG_ATTR_USER_FLAGS = 11
|
||||
_SECPKG_ATTR_NEGOTIATION_INFO = 12
|
||||
_SECPKG_ATTR_NATIVE_NAMES = 13
|
||||
_SECPKG_ATTR_FLAGS = 14
|
||||
)
|
||||
|
||||
type SecPkgInfo struct {
|
||||
Capabilities uint32
|
||||
Version uint16
|
||||
RPCID uint16
|
||||
MaxToken uint32
|
||||
Name *uint16
|
||||
Comment *uint16
|
||||
}
|
||||
|
||||
type _SecPkgContext_Sizes struct {
|
||||
MaxToken uint32
|
||||
MaxSignature uint32
|
||||
BlockSize uint32
|
||||
SecurityTrailer uint32
|
||||
}
|
||||
|
||||
//sys QuerySecurityPackageInfo(pkgname *uint16, pkginfo **SecPkgInfo) (ret syscall.Errno) = secur32.QuerySecurityPackageInfoW
|
||||
//sys FreeContextBuffer(buf *byte) (ret syscall.Errno) = secur32.FreeContextBuffer
|
||||
|
||||
const (
|
||||
SECPKG_CRED_INBOUND = 1
|
||||
SECPKG_CRED_OUTBOUND = 2
|
||||
SECPKG_CRED_BOTH = (SECPKG_CRED_OUTBOUND | SECPKG_CRED_INBOUND)
|
||||
|
||||
SEC_WINNT_AUTH_IDENTITY_UNICODE = 0x2
|
||||
)
|
||||
|
||||
type SEC_WINNT_AUTH_IDENTITY struct {
|
||||
User *uint16
|
||||
UserLength uint32
|
||||
Domain *uint16
|
||||
DomainLength uint32
|
||||
Password *uint16
|
||||
PasswordLength uint32
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
type LUID struct {
|
||||
LowPart uint32
|
||||
HighPart int32
|
||||
}
|
||||
|
||||
type CredHandle struct {
|
||||
Lower uintptr
|
||||
Upper uintptr
|
||||
}
|
||||
|
||||
//sys AcquireCredentialsHandle(principal *uint16, pkgname *uint16, creduse uint32, logonid *LUID, authdata *byte, getkeyfn uintptr, getkeyarg uintptr, handle *CredHandle, expiry *syscall.Filetime) (ret syscall.Errno) = secur32.AcquireCredentialsHandleW
|
||||
//sys FreeCredentialsHandle(handle *CredHandle) (ret syscall.Errno) = secur32.FreeCredentialsHandle
|
||||
|
||||
const (
|
||||
SECURITY_NATIVE_DREP = 16
|
||||
|
||||
SECBUFFER_DATA = 1
|
||||
SECBUFFER_TOKEN = 2
|
||||
SECBUFFER_PKG_PARAMS = 3
|
||||
SECBUFFER_MISSING = 4
|
||||
SECBUFFER_EXTRA = 5
|
||||
SECBUFFER_STREAM_TRAILER = 6
|
||||
SECBUFFER_STREAM_HEADER = 7
|
||||
SECBUFFER_PADDING = 9
|
||||
SECBUFFER_STREAM = 10
|
||||
SECBUFFER_READONLY = 0x80000000
|
||||
SECBUFFER_ATTRMASK = 0xf0000000
|
||||
SECBUFFER_VERSION = 0
|
||||
SECBUFFER_EMPTY = 0
|
||||
|
||||
ISC_REQ_DELEGATE = 1
|
||||
ISC_REQ_MUTUAL_AUTH = 2
|
||||
ISC_REQ_REPLAY_DETECT = 4
|
||||
ISC_REQ_SEQUENCE_DETECT = 8
|
||||
ISC_REQ_CONFIDENTIALITY = 16
|
||||
ISC_REQ_USE_SESSION_KEY = 32
|
||||
ISC_REQ_PROMPT_FOR_CREDS = 64
|
||||
ISC_REQ_USE_SUPPLIED_CREDS = 128
|
||||
ISC_REQ_ALLOCATE_MEMORY = 256
|
||||
ISC_REQ_USE_DCE_STYLE = 512
|
||||
ISC_REQ_DATAGRAM = 1024
|
||||
ISC_REQ_CONNECTION = 2048
|
||||
ISC_REQ_EXTENDED_ERROR = 16384
|
||||
ISC_REQ_STREAM = 32768
|
||||
ISC_REQ_INTEGRITY = 65536
|
||||
ISC_REQ_MANUAL_CRED_VALIDATION = 524288
|
||||
ISC_REQ_HTTP = 268435456
|
||||
|
||||
ASC_REQ_DELEGATE = 1
|
||||
ASC_REQ_MUTUAL_AUTH = 2
|
||||
ASC_REQ_REPLAY_DETECT = 4
|
||||
ASC_REQ_SEQUENCE_DETECT = 8
|
||||
ASC_REQ_CONFIDENTIALITY = 16
|
||||
ASC_REQ_USE_SESSION_KEY = 32
|
||||
ASC_REQ_ALLOCATE_MEMORY = 256
|
||||
ASC_REQ_USE_DCE_STYLE = 512
|
||||
ASC_REQ_DATAGRAM = 1024
|
||||
ASC_REQ_CONNECTION = 2048
|
||||
ASC_REQ_EXTENDED_ERROR = 32768
|
||||
ASC_REQ_STREAM = 65536
|
||||
ASC_REQ_INTEGRITY = 131072
|
||||
)
|
||||
|
||||
type CtxtHandle struct {
|
||||
Lower uintptr
|
||||
Upper uintptr
|
||||
}
|
||||
|
||||
type SecBuffer struct {
|
||||
BufferSize uint32
|
||||
BufferType uint32
|
||||
Buffer *byte
|
||||
}
|
||||
|
||||
type SecBufferDesc struct {
|
||||
Version uint32
|
||||
BuffersCount uint32
|
||||
Buffers *SecBuffer
|
||||
}
|
||||
|
||||
//sys InitializeSecurityContext(credential *CredHandle, context *CtxtHandle, targname *uint16, contextreq uint32, reserved1 uint32, targdatarep uint32, input *SecBufferDesc, reserved2 uint32, newcontext *CtxtHandle, output *SecBufferDesc, contextattr *uint32, expiry *syscall.Filetime) (ret syscall.Errno) = secur32.InitializeSecurityContextW
|
||||
//sys AcceptSecurityContext(credential *CredHandle, context *CtxtHandle, input *SecBufferDesc, contextreq uint32, targdatarep uint32, newcontext *CtxtHandle, output *SecBufferDesc, contextattr *uint32, expiry *syscall.Filetime) (ret syscall.Errno) = secur32.AcceptSecurityContext
|
||||
//sys CompleteAuthToken(context *CtxtHandle, token *SecBufferDesc) (ret syscall.Errno) = secur32.CompleteAuthToken
|
||||
//sys DeleteSecurityContext(context *CtxtHandle) (ret syscall.Errno) = secur32.DeleteSecurityContext
|
||||
//sys ImpersonateSecurityContext(context *CtxtHandle) (ret syscall.Errno) = secur32.ImpersonateSecurityContext
|
||||
//sys RevertSecurityContext(context *CtxtHandle) (ret syscall.Errno) = secur32.RevertSecurityContext
|
||||
//sys QueryContextAttributes(context *CtxtHandle, attribute uint32, buf *byte) (ret syscall.Errno) = secur32.QueryContextAttributesW
|
||||
//sys EncryptMessage(context *CtxtHandle, qop uint32, message *SecBufferDesc, messageseqno uint32) (ret syscall.Errno) = secur32.EncryptMessage
|
||||
//sys DecryptMessage(context *CtxtHandle, message *SecBufferDesc, messageseqno uint32, qop *uint32) (ret syscall.Errno) = secur32.DecryptMessage
|
||||
//sys ApplyControlToken(context *CtxtHandle, input *SecBufferDesc) (ret syscall.Errno) = secur32.ApplyControlToken
|
||||
//sys MakeSignature(context *CtxtHandle, qop uint32, message *SecBufferDesc, messageseqno uint32) (ret syscall.Errno) = secur32.MakeSignature
|
||||
//sys VerifySignature(context *CtxtHandle, message *SecBufferDesc, messageseqno uint32, qop *uint32) (ret syscall.Errno) = secur32.VerifySignature
|
152
vendor/github.com/alexbrainman/sspi/zsyscall_windows.go
generated
vendored
Normal file
152
vendor/github.com/alexbrainman/sspi/zsyscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||
|
||||
package sspi
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modsecur32 = syscall.NewLazyDLL("secur32.dll")
|
||||
|
||||
procQuerySecurityPackageInfoW = modsecur32.NewProc("QuerySecurityPackageInfoW")
|
||||
procFreeContextBuffer = modsecur32.NewProc("FreeContextBuffer")
|
||||
procAcquireCredentialsHandleW = modsecur32.NewProc("AcquireCredentialsHandleW")
|
||||
procFreeCredentialsHandle = modsecur32.NewProc("FreeCredentialsHandle")
|
||||
procInitializeSecurityContextW = modsecur32.NewProc("InitializeSecurityContextW")
|
||||
procAcceptSecurityContext = modsecur32.NewProc("AcceptSecurityContext")
|
||||
procCompleteAuthToken = modsecur32.NewProc("CompleteAuthToken")
|
||||
procDeleteSecurityContext = modsecur32.NewProc("DeleteSecurityContext")
|
||||
procImpersonateSecurityContext = modsecur32.NewProc("ImpersonateSecurityContext")
|
||||
procRevertSecurityContext = modsecur32.NewProc("RevertSecurityContext")
|
||||
procQueryContextAttributesW = modsecur32.NewProc("QueryContextAttributesW")
|
||||
procEncryptMessage = modsecur32.NewProc("EncryptMessage")
|
||||
procDecryptMessage = modsecur32.NewProc("DecryptMessage")
|
||||
procApplyControlToken = modsecur32.NewProc("ApplyControlToken")
|
||||
procMakeSignature = modsecur32.NewProc("MakeSignature")
|
||||
procVerifySignature = modsecur32.NewProc("VerifySignature")
|
||||
)
|
||||
|
||||
func QuerySecurityPackageInfo(pkgname *uint16, pkginfo **SecPkgInfo) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procQuerySecurityPackageInfoW.Addr(), 2, uintptr(unsafe.Pointer(pkgname)), uintptr(unsafe.Pointer(pkginfo)), 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func FreeContextBuffer(buf *byte) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procFreeContextBuffer.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func AcquireCredentialsHandle(principal *uint16, pkgname *uint16, creduse uint32, logonid *LUID, authdata *byte, getkeyfn uintptr, getkeyarg uintptr, handle *CredHandle, expiry *syscall.Filetime) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall9(procAcquireCredentialsHandleW.Addr(), 9, uintptr(unsafe.Pointer(principal)), uintptr(unsafe.Pointer(pkgname)), uintptr(creduse), uintptr(unsafe.Pointer(logonid)), uintptr(unsafe.Pointer(authdata)), uintptr(getkeyfn), uintptr(getkeyarg), uintptr(unsafe.Pointer(handle)), uintptr(unsafe.Pointer(expiry)))
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func FreeCredentialsHandle(handle *CredHandle) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procFreeCredentialsHandle.Addr(), 1, uintptr(unsafe.Pointer(handle)), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func InitializeSecurityContext(credential *CredHandle, context *CtxtHandle, targname *uint16, contextreq uint32, reserved1 uint32, targdatarep uint32, input *SecBufferDesc, reserved2 uint32, newcontext *CtxtHandle, output *SecBufferDesc, contextattr *uint32, expiry *syscall.Filetime) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall12(procInitializeSecurityContextW.Addr(), 12, uintptr(unsafe.Pointer(credential)), uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(targname)), uintptr(contextreq), uintptr(reserved1), uintptr(targdatarep), uintptr(unsafe.Pointer(input)), uintptr(reserved2), uintptr(unsafe.Pointer(newcontext)), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(contextattr)), uintptr(unsafe.Pointer(expiry)))
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func AcceptSecurityContext(credential *CredHandle, context *CtxtHandle, input *SecBufferDesc, contextreq uint32, targdatarep uint32, newcontext *CtxtHandle, output *SecBufferDesc, contextattr *uint32, expiry *syscall.Filetime) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall9(procAcceptSecurityContext.Addr(), 9, uintptr(unsafe.Pointer(credential)), uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(input)), uintptr(contextreq), uintptr(targdatarep), uintptr(unsafe.Pointer(newcontext)), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(contextattr)), uintptr(unsafe.Pointer(expiry)))
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func CompleteAuthToken(context *CtxtHandle, token *SecBufferDesc) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procCompleteAuthToken.Addr(), 2, uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(token)), 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteSecurityContext(context *CtxtHandle) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procDeleteSecurityContext.Addr(), 1, uintptr(unsafe.Pointer(context)), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func ImpersonateSecurityContext(context *CtxtHandle) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procImpersonateSecurityContext.Addr(), 1, uintptr(unsafe.Pointer(context)), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func RevertSecurityContext(context *CtxtHandle) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procRevertSecurityContext.Addr(), 1, uintptr(unsafe.Pointer(context)), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func QueryContextAttributes(context *CtxtHandle, attribute uint32, buf *byte) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procQueryContextAttributesW.Addr(), 3, uintptr(unsafe.Pointer(context)), uintptr(attribute), uintptr(unsafe.Pointer(buf)))
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func EncryptMessage(context *CtxtHandle, qop uint32, message *SecBufferDesc, messageseqno uint32) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall6(procEncryptMessage.Addr(), 4, uintptr(unsafe.Pointer(context)), uintptr(qop), uintptr(unsafe.Pointer(message)), uintptr(messageseqno), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func DecryptMessage(context *CtxtHandle, message *SecBufferDesc, messageseqno uint32, qop *uint32) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall6(procDecryptMessage.Addr(), 4, uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(message)), uintptr(messageseqno), uintptr(unsafe.Pointer(qop)), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func ApplyControlToken(context *CtxtHandle, input *SecBufferDesc) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall(procApplyControlToken.Addr(), 2, uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(input)), 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func MakeSignature(context *CtxtHandle, qop uint32, message *SecBufferDesc, messageseqno uint32) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall6(procMakeSignature.Addr(), 4, uintptr(unsafe.Pointer(context)), uintptr(qop), uintptr(unsafe.Pointer(message)), uintptr(messageseqno), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func VerifySignature(context *CtxtHandle, message *SecBufferDesc, messageseqno uint32, qop *uint32) (ret syscall.Errno) {
|
||||
r0, _, _ := syscall.Syscall6(procVerifySignature.Addr(), 4, uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(message)), uintptr(messageseqno), uintptr(unsafe.Pointer(qop)), 0, 0)
|
||||
ret = syscall.Errno(r0)
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue
Block a user