aboutsummaryrefslogtreecommitdiff
path: root/vendor/gopkg.in/mgo.v2/internal
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/mgo.v2/internal')
-rw-r--r--vendor/gopkg.in/mgo.v2/internal/sasl/sasl.c77
-rw-r--r--vendor/gopkg.in/mgo.v2/internal/sasl/sasl.go138
-rw-r--r--vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.c118
-rw-r--r--vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.go140
-rw-r--r--vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.h7
-rw-r--r--vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.c96
-rw-r--r--vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.h70
-rw-r--r--vendor/gopkg.in/mgo.v2/internal/scram/scram.go266
8 files changed, 912 insertions, 0 deletions
diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.c b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.c
new file mode 100644
index 0000000..8be0bc4
--- /dev/null
+++ b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.c
@@ -0,0 +1,77 @@
+// +build !windows
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sasl/sasl.h>
+
+static int mgo_sasl_simple(void *context, int id, const char **result, unsigned int *len)
+{
+ if (!result) {
+ return SASL_BADPARAM;
+ }
+ switch (id) {
+ case SASL_CB_USER:
+ *result = (char *)context;
+ break;
+ case SASL_CB_AUTHNAME:
+ *result = (char *)context;
+ break;
+ case SASL_CB_LANGUAGE:
+ *result = NULL;
+ break;
+ default:
+ return SASL_BADPARAM;
+ }
+ if (len) {
+ *len = *result ? strlen(*result) : 0;
+ }
+ return SASL_OK;
+}
+
+typedef int (*callback)(void);
+
+static int mgo_sasl_secret(sasl_conn_t *conn, void *context, int id, sasl_secret_t **result)
+{
+ if (!conn || !result || id != SASL_CB_PASS) {
+ return SASL_BADPARAM;
+ }
+ *result = (sasl_secret_t *)context;
+ return SASL_OK;
+}
+
+sasl_callback_t *mgo_sasl_callbacks(const char *username, const char *password)
+{
+ sasl_callback_t *cb = malloc(4 * sizeof(sasl_callback_t));
+ int n = 0;
+
+ size_t len = strlen(password);
+ sasl_secret_t *secret = (sasl_secret_t*)malloc(sizeof(sasl_secret_t) + len);
+ if (!secret) {
+ free(cb);
+ return NULL;
+ }
+ strcpy((char *)secret->data, password);
+ secret->len = len;
+
+ cb[n].id = SASL_CB_PASS;
+ cb[n].proc = (callback)&mgo_sasl_secret;
+ cb[n].context = secret;
+ n++;
+
+ cb[n].id = SASL_CB_USER;
+ cb[n].proc = (callback)&mgo_sasl_simple;
+ cb[n].context = (char*)username;
+ n++;
+
+ cb[n].id = SASL_CB_AUTHNAME;
+ cb[n].proc = (callback)&mgo_sasl_simple;
+ cb[n].context = (char*)username;
+ n++;
+
+ cb[n].id = SASL_CB_LIST_END;
+ cb[n].proc = NULL;
+ cb[n].context = NULL;
+
+ return cb;
+}
diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.go b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.go
new file mode 100644
index 0000000..8375ddd
--- /dev/null
+++ b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl.go
@@ -0,0 +1,138 @@
+// Package sasl is an implementation detail of the mgo package.
+//
+// This package is not meant to be used by itself.
+//
+
+// +build !windows
+
+package sasl
+
+// #cgo LDFLAGS: -lsasl2
+//
+// struct sasl_conn {};
+//
+// #include <stdlib.h>
+// #include <sasl/sasl.h>
+//
+// sasl_callback_t *mgo_sasl_callbacks(const char *username, const char *password);
+//
+import "C"
+
+import (
+ "fmt"
+ "strings"
+ "sync"
+ "unsafe"
+)
+
+type saslStepper interface {
+ Step(serverData []byte) (clientData []byte, done bool, err error)
+ Close()
+}
+
+type saslSession struct {
+ conn *C.sasl_conn_t
+ step int
+ mech string
+
+ cstrings []*C.char
+ callbacks *C.sasl_callback_t
+}
+
+var initError error
+var initOnce sync.Once
+
+func initSASL() {
+ rc := C.sasl_client_init(nil)
+ if rc != C.SASL_OK {
+ initError = saslError(rc, nil, "cannot initialize SASL library")
+ }
+}
+
+func New(username, password, mechanism, service, host string) (saslStepper, error) {
+ initOnce.Do(initSASL)
+ if initError != nil {
+ return nil, initError
+ }
+
+ ss := &saslSession{mech: mechanism}
+ if service == "" {
+ service = "mongodb"
+ }
+ if i := strings.Index(host, ":"); i >= 0 {
+ host = host[:i]
+ }
+ ss.callbacks = C.mgo_sasl_callbacks(ss.cstr(username), ss.cstr(password))
+ rc := C.sasl_client_new(ss.cstr(service), ss.cstr(host), nil, nil, ss.callbacks, 0, &ss.conn)
+ if rc != C.SASL_OK {
+ ss.Close()
+ return nil, saslError(rc, nil, "cannot create new SASL client")
+ }
+ return ss, nil
+}
+
+func (ss *saslSession) cstr(s string) *C.char {
+ cstr := C.CString(s)
+ ss.cstrings = append(ss.cstrings, cstr)
+ return cstr
+}
+
+func (ss *saslSession) Close() {
+ for _, cstr := range ss.cstrings {
+ C.free(unsafe.Pointer(cstr))
+ }
+ ss.cstrings = nil
+
+ if ss.callbacks != nil {
+ C.free(unsafe.Pointer(ss.callbacks))
+ }
+
+ // The documentation of SASL dispose makes it clear that this should only
+ // be done when the connection is done, not when the authentication phase
+ // is done, because an encryption layer may have been negotiated.
+ // Even then, we'll do this for now, because it's simpler and prevents
+ // keeping track of this state for every socket. If it breaks, we'll fix it.
+ C.sasl_dispose(&ss.conn)
+}
+
+func (ss *saslSession) Step(serverData []byte) (clientData []byte, done bool, err error) {
+ ss.step++
+ if ss.step > 10 {
+ return nil, false, fmt.Errorf("too many SASL steps without authentication")
+ }
+ var cclientData *C.char
+ var cclientDataLen C.uint
+ var rc C.int
+ if ss.step == 1 {
+ var mechanism *C.char // ignored - must match cred
+ rc = C.sasl_client_start(ss.conn, ss.cstr(ss.mech), nil, &cclientData, &cclientDataLen, &mechanism)
+ } else {
+ var cserverData *C.char
+ var cserverDataLen C.uint
+ if len(serverData) > 0 {
+ cserverData = (*C.char)(unsafe.Pointer(&serverData[0]))
+ cserverDataLen = C.uint(len(serverData))
+ }
+ rc = C.sasl_client_step(ss.conn, cserverData, cserverDataLen, nil, &cclientData, &cclientDataLen)
+ }
+ if cclientData != nil && cclientDataLen > 0 {
+ clientData = C.GoBytes(unsafe.Pointer(cclientData), C.int(cclientDataLen))
+ }
+ if rc == C.SASL_OK {
+ return clientData, true, nil
+ }
+ if rc == C.SASL_CONTINUE {
+ return clientData, false, nil
+ }
+ return nil, false, saslError(rc, ss.conn, "cannot establish SASL session")
+}
+
+func saslError(rc C.int, conn *C.sasl_conn_t, msg string) error {
+ var detail string
+ if conn == nil {
+ detail = C.GoString(C.sasl_errstring(rc, nil, nil))
+ } else {
+ detail = C.GoString(C.sasl_errdetail(conn))
+ }
+ return fmt.Errorf(msg + ": " + detail)
+}
diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.c b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.c
new file mode 100644
index 0000000..dd6a88a
--- /dev/null
+++ b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.c
@@ -0,0 +1,118 @@
+#include "sasl_windows.h"
+
+static const LPSTR SSPI_PACKAGE_NAME = "kerberos";
+
+SECURITY_STATUS SEC_ENTRY sspi_acquire_credentials_handle(CredHandle *cred_handle, char *username, char *password, char *domain)
+{
+ SEC_WINNT_AUTH_IDENTITY auth_identity;
+ SECURITY_INTEGER ignored;
+
+ auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
+ auth_identity.User = (LPSTR) username;
+ auth_identity.UserLength = strlen(username);
+ auth_identity.Password = (LPSTR) password;
+ auth_identity.PasswordLength = strlen(password);
+ auth_identity.Domain = (LPSTR) domain;
+ auth_identity.DomainLength = strlen(domain);
+ return call_sspi_acquire_credentials_handle(NULL, SSPI_PACKAGE_NAME, SECPKG_CRED_OUTBOUND, NULL, &auth_identity, NULL, NULL, cred_handle, &ignored);
+}
+
+int sspi_step(CredHandle *cred_handle, int has_context, CtxtHandle *context, PVOID *buffer, ULONG *buffer_length, char *target)
+{
+ SecBufferDesc inbuf;
+ SecBuffer in_bufs[1];
+ SecBufferDesc outbuf;
+ SecBuffer out_bufs[1];
+
+ if (has_context > 0) {
+ // If we already have a context, we now have data to send.
+ // Put this data in an inbuf.
+ inbuf.ulVersion = SECBUFFER_VERSION;
+ inbuf.cBuffers = 1;
+ inbuf.pBuffers = in_bufs;
+ in_bufs[0].pvBuffer = *buffer;
+ in_bufs[0].cbBuffer = *buffer_length;
+ in_bufs[0].BufferType = SECBUFFER_TOKEN;
+ }
+
+ outbuf.ulVersion = SECBUFFER_VERSION;
+ outbuf.cBuffers = 1;
+ outbuf.pBuffers = out_bufs;
+ out_bufs[0].pvBuffer = NULL;
+ out_bufs[0].cbBuffer = 0;
+ out_bufs[0].BufferType = SECBUFFER_TOKEN;
+
+ ULONG context_attr = 0;
+
+ int ret = call_sspi_initialize_security_context(cred_handle,
+ has_context > 0 ? context : NULL,
+ (LPSTR) target,
+ ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MUTUAL_AUTH,
+ 0,
+ SECURITY_NETWORK_DREP,
+ has_context > 0 ? &inbuf : NULL,
+ 0,
+ context,
+ &outbuf,
+ &context_attr,
+ NULL);
+
+ *buffer = malloc(out_bufs[0].cbBuffer);
+ *buffer_length = out_bufs[0].cbBuffer;
+ memcpy(*buffer, out_bufs[0].pvBuffer, *buffer_length);
+
+ return ret;
+}
+
+int sspi_send_client_authz_id(CtxtHandle *context, PVOID *buffer, ULONG *buffer_length, char *user_plus_realm)
+{
+ SecPkgContext_Sizes sizes;
+ SECURITY_STATUS status = call_sspi_query_context_attributes(context, SECPKG_ATTR_SIZES, &sizes);
+
+ if (status != SEC_E_OK) {
+ return status;
+ }
+
+ size_t user_plus_realm_length = strlen(user_plus_realm);
+ int msgSize = 4 + user_plus_realm_length;
+ char *msg = malloc((sizes.cbSecurityTrailer + msgSize + sizes.cbBlockSize) * sizeof(char));
+ msg[sizes.cbSecurityTrailer + 0] = 1;
+ msg[sizes.cbSecurityTrailer + 1] = 0;
+ msg[sizes.cbSecurityTrailer + 2] = 0;
+ msg[sizes.cbSecurityTrailer + 3] = 0;
+ memcpy(&msg[sizes.cbSecurityTrailer + 4], user_plus_realm, user_plus_realm_length);
+
+ SecBuffer wrapBufs[3];
+ SecBufferDesc wrapBufDesc;
+ wrapBufDesc.cBuffers = 3;
+ wrapBufDesc.pBuffers = wrapBufs;
+ wrapBufDesc.ulVersion = SECBUFFER_VERSION;
+
+ wrapBufs[0].cbBuffer = sizes.cbSecurityTrailer;
+ wrapBufs[0].BufferType = SECBUFFER_TOKEN;
+ wrapBufs[0].pvBuffer = msg;
+
+ wrapBufs[1].cbBuffer = msgSize;
+ wrapBufs[1].BufferType = SECBUFFER_DATA;
+ wrapBufs[1].pvBuffer = msg + sizes.cbSecurityTrailer;
+
+ wrapBufs[2].cbBuffer = sizes.cbBlockSize;
+ wrapBufs[2].BufferType = SECBUFFER_PADDING;
+ wrapBufs[2].pvBuffer = msg + sizes.cbSecurityTrailer + msgSize;
+
+ status = call_sspi_encrypt_message(context, SECQOP_WRAP_NO_ENCRYPT, &wrapBufDesc, 0);
+ if (status != SEC_E_OK) {
+ free(msg);
+ return status;
+ }
+
+ *buffer_length = wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer + wrapBufs[2].cbBuffer;
+ *buffer = malloc(*buffer_length);
+
+ memcpy(*buffer, wrapBufs[0].pvBuffer, wrapBufs[0].cbBuffer);
+ memcpy(*buffer + wrapBufs[0].cbBuffer, wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer);
+ memcpy(*buffer + wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer, wrapBufs[2].pvBuffer, wrapBufs[2].cbBuffer);
+
+ free(msg);
+ return SEC_E_OK;
+}
diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.go b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.go
new file mode 100644
index 0000000..3302cfe
--- /dev/null
+++ b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.go
@@ -0,0 +1,140 @@
+package sasl
+
+// #include "sasl_windows.h"
+import "C"
+
+import (
+ "fmt"
+ "strings"
+ "sync"
+ "unsafe"
+)
+
+type saslStepper interface {
+ Step(serverData []byte) (clientData []byte, done bool, err error)
+ Close()
+}
+
+type saslSession struct {
+ // Credentials
+ mech string
+ service string
+ host string
+ userPlusRealm string
+ target string
+ domain string
+
+ // Internal state
+ authComplete bool
+ errored bool
+ step int
+
+ // C internal state
+ credHandle C.CredHandle
+ context C.CtxtHandle
+ hasContext C.int
+
+ // Keep track of pointers we need to explicitly free
+ stringsToFree []*C.char
+}
+
+var initError error
+var initOnce sync.Once
+
+func initSSPI() {
+ rc := C.load_secur32_dll()
+ if rc != 0 {
+ initError = fmt.Errorf("Error loading libraries: %v", rc)
+ }
+}
+
+func New(username, password, mechanism, service, host string) (saslStepper, error) {
+ initOnce.Do(initSSPI)
+ ss := &saslSession{mech: mechanism, hasContext: 0, userPlusRealm: username}
+ if service == "" {
+ service = "mongodb"
+ }
+ if i := strings.Index(host, ":"); i >= 0 {
+ host = host[:i]
+ }
+ ss.service = service
+ ss.host = host
+
+ usernameComponents := strings.Split(username, "@")
+ if len(usernameComponents) < 2 {
+ return nil, fmt.Errorf("Username '%v' doesn't contain a realm!", username)
+ }
+ user := usernameComponents[0]
+ ss.domain = usernameComponents[1]
+ ss.target = fmt.Sprintf("%s/%s", ss.service, ss.host)
+
+ var status C.SECURITY_STATUS
+ // Step 0: call AcquireCredentialsHandle to get a nice SSPI CredHandle
+ if len(password) > 0 {
+ status = C.sspi_acquire_credentials_handle(&ss.credHandle, ss.cstr(user), ss.cstr(password), ss.cstr(ss.domain))
+ } else {
+ status = C.sspi_acquire_credentials_handle(&ss.credHandle, ss.cstr(user), nil, ss.cstr(ss.domain))
+ }
+ if status != C.SEC_E_OK {
+ ss.errored = true
+ return nil, fmt.Errorf("Couldn't create new SSPI client, error code %v", status)
+ }
+ return ss, nil
+}
+
+func (ss *saslSession) cstr(s string) *C.char {
+ cstr := C.CString(s)
+ ss.stringsToFree = append(ss.stringsToFree, cstr)
+ return cstr
+}
+
+func (ss *saslSession) Close() {
+ for _, cstr := range ss.stringsToFree {
+ C.free(unsafe.Pointer(cstr))
+ }
+}
+
+func (ss *saslSession) Step(serverData []byte) (clientData []byte, done bool, err error) {
+ ss.step++
+ if ss.step > 10 {
+ return nil, false, fmt.Errorf("too many SSPI steps without authentication")
+ }
+ var buffer C.PVOID
+ var bufferLength C.ULONG
+ if len(serverData) > 0 {
+ buffer = (C.PVOID)(unsafe.Pointer(&serverData[0]))
+ bufferLength = C.ULONG(len(serverData))
+ }
+ var status C.int
+ if ss.authComplete {
+ // Step 3: last bit of magic to use the correct server credentials
+ status = C.sspi_send_client_authz_id(&ss.context, &buffer, &bufferLength, ss.cstr(ss.userPlusRealm))
+ } else {
+ // Step 1 + Step 2: set up security context with the server and TGT
+ status = C.sspi_step(&ss.credHandle, ss.hasContext, &ss.context, &buffer, &bufferLength, ss.cstr(ss.target))
+ }
+ if buffer != C.PVOID(nil) {
+ defer C.free(unsafe.Pointer(buffer))
+ }
+ if status != C.SEC_E_OK && status != C.SEC_I_CONTINUE_NEEDED {
+ ss.errored = true
+ return nil, false, ss.handleSSPIErrorCode(status)
+ }
+
+ clientData = C.GoBytes(unsafe.Pointer(buffer), C.int(bufferLength))
+ if status == C.SEC_E_OK {
+ ss.authComplete = true
+ return clientData, true, nil
+ } else {
+ ss.hasContext = 1
+ return clientData, false, nil
+ }
+}
+
+func (ss *saslSession) handleSSPIErrorCode(code C.int) error {
+ switch {
+ case code == C.SEC_E_TARGET_UNKNOWN:
+ return fmt.Errorf("Target %v@%v not found", ss.target, ss.domain)
+ }
+ return fmt.Errorf("Unknown error doing step %v, error code %v", ss.step, code)
+}
diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.h b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.h
new file mode 100644
index 0000000..94321b2
--- /dev/null
+++ b/vendor/gopkg.in/mgo.v2/internal/sasl/sasl_windows.h
@@ -0,0 +1,7 @@
+#include <windows.h>
+
+#include "sspi_windows.h"
+
+SECURITY_STATUS SEC_ENTRY sspi_acquire_credentials_handle(CredHandle* cred_handle, char* username, char* password, char* domain);
+int sspi_step(CredHandle* cred_handle, int has_context, CtxtHandle* context, PVOID* buffer, ULONG* buffer_length, char* target);
+int sspi_send_client_authz_id(CtxtHandle* context, PVOID* buffer, ULONG* buffer_length, char* user_plus_realm);
diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.c b/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.c
new file mode 100644
index 0000000..63f9a6f
--- /dev/null
+++ b/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.c
@@ -0,0 +1,96 @@
+// Code adapted from the NodeJS kerberos library:
+//
+// https://github.com/christkv/kerberos/tree/master/lib/win32/kerberos_sspi.c
+//
+// Under the terms of the Apache License, Version 2.0:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+#include <stdlib.h>
+
+#include "sspi_windows.h"
+
+static HINSTANCE sspi_secur32_dll = NULL;
+
+int load_secur32_dll()
+{
+ sspi_secur32_dll = LoadLibrary("secur32.dll");
+ if (sspi_secur32_dll == NULL) {
+ return GetLastError();
+ }
+ return 0;
+}
+
+SECURITY_STATUS SEC_ENTRY call_sspi_encrypt_message(PCtxtHandle phContext, unsigned long fQOP, PSecBufferDesc pMessage, unsigned long MessageSeqNo)
+{
+ if (sspi_secur32_dll == NULL) {
+ return -1;
+ }
+ encryptMessage_fn pfn_encryptMessage = (encryptMessage_fn) GetProcAddress(sspi_secur32_dll, "EncryptMessage");
+ if (!pfn_encryptMessage) {
+ return -2;
+ }
+ return (*pfn_encryptMessage)(phContext, fQOP, pMessage, MessageSeqNo);
+}
+
+SECURITY_STATUS SEC_ENTRY call_sspi_acquire_credentials_handle(
+ LPSTR pszPrincipal, LPSTR pszPackage, unsigned long fCredentialUse,
+ void *pvLogonId, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument,
+ PCredHandle phCredential, PTimeStamp ptsExpiry)
+{
+ if (sspi_secur32_dll == NULL) {
+ return -1;
+ }
+ acquireCredentialsHandle_fn pfn_acquireCredentialsHandle;
+#ifdef _UNICODE
+ pfn_acquireCredentialsHandle = (acquireCredentialsHandle_fn) GetProcAddress(sspi_secur32_dll, "AcquireCredentialsHandleW");
+#else
+ pfn_acquireCredentialsHandle = (acquireCredentialsHandle_fn) GetProcAddress(sspi_secur32_dll, "AcquireCredentialsHandleA");
+#endif
+ if (!pfn_acquireCredentialsHandle) {
+ return -2;
+ }
+ return (*pfn_acquireCredentialsHandle)(
+ pszPrincipal, pszPackage, fCredentialUse, pvLogonId, pAuthData,
+ pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry);
+}
+
+SECURITY_STATUS SEC_ENTRY call_sspi_initialize_security_context(
+ PCredHandle phCredential, PCtxtHandle phContext, LPSTR pszTargetName,
+ unsigned long fContextReq, unsigned long Reserved1, unsigned long TargetDataRep,
+ PSecBufferDesc pInput, unsigned long Reserved2, PCtxtHandle phNewContext,
+ PSecBufferDesc pOutput, unsigned long *pfContextAttr, PTimeStamp ptsExpiry)
+{
+ if (sspi_secur32_dll == NULL) {
+ return -1;
+ }
+ initializeSecurityContext_fn pfn_initializeSecurityContext;
+#ifdef _UNICODE
+ pfn_initializeSecurityContext = (initializeSecurityContext_fn) GetProcAddress(sspi_secur32_dll, "InitializeSecurityContextW");
+#else
+ pfn_initializeSecurityContext = (initializeSecurityContext_fn) GetProcAddress(sspi_secur32_dll, "InitializeSecurityContextA");
+#endif
+ if (!pfn_initializeSecurityContext) {
+ return -2;
+ }
+ return (*pfn_initializeSecurityContext)(
+ phCredential, phContext, pszTargetName, fContextReq, Reserved1, TargetDataRep,
+ pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
+}
+
+SECURITY_STATUS SEC_ENTRY call_sspi_query_context_attributes(PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer)
+{
+ if (sspi_secur32_dll == NULL) {
+ return -1;
+ }
+ queryContextAttributes_fn pfn_queryContextAttributes;
+#ifdef _UNICODE
+ pfn_queryContextAttributes = (queryContextAttributes_fn) GetProcAddress(sspi_secur32_dll, "QueryContextAttributesW");
+#else
+ pfn_queryContextAttributes = (queryContextAttributes_fn) GetProcAddress(sspi_secur32_dll, "QueryContextAttributesA");
+#endif
+ if (!pfn_queryContextAttributes) {
+ return -2;
+ }
+ return (*pfn_queryContextAttributes)(phContext, ulAttribute, pBuffer);
+}
diff --git a/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.h b/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.h
new file mode 100644
index 0000000..d283270
--- /dev/null
+++ b/vendor/gopkg.in/mgo.v2/internal/sasl/sspi_windows.h
@@ -0,0 +1,70 @@
+// Code adapted from the NodeJS kerberos library:
+//
+// https://github.com/christkv/kerberos/tree/master/lib/win32/kerberos_sspi.h
+//
+// Under the terms of the Apache License, Version 2.0:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+#ifndef SSPI_WINDOWS_H
+#define SSPI_WINDOWS_H
+
+#define SECURITY_WIN32 1
+
+#include <windows.h>
+#include <sspi.h>
+
+int load_secur32_dll();
+
+SECURITY_STATUS SEC_ENTRY call_sspi_encrypt_message(PCtxtHandle phContext, unsigned long fQOP, PSecBufferDesc pMessage, unsigned long MessageSeqNo);
+
+typedef DWORD (WINAPI *encryptMessage_fn)(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo);
+
+SECURITY_STATUS SEC_ENTRY call_sspi_acquire_credentials_handle(
+ LPSTR pszPrincipal, // Name of principal
+ LPSTR pszPackage, // Name of package
+ unsigned long fCredentialUse, // Flags indicating use
+ void *pvLogonId, // Pointer to logon ID
+ void *pAuthData, // Package specific data
+ SEC_GET_KEY_FN pGetKeyFn, // Pointer to GetKey() func
+ void *pvGetKeyArgument, // Value to pass to GetKey()
+ PCredHandle phCredential, // (out) Cred Handle
+ PTimeStamp ptsExpiry // (out) Lifetime (optional)
+);
+
+typedef DWORD (WINAPI *acquireCredentialsHandle_fn)(
+ LPSTR pszPrincipal, LPSTR pszPackage, unsigned long fCredentialUse,
+ void *pvLogonId, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument,
+ PCredHandle phCredential, PTimeStamp ptsExpiry
+);
+
+SECURITY_STATUS SEC_ENTRY call_sspi_initialize_security_context(
+ PCredHandle phCredential, // Cred to base context
+ PCtxtHandle phContext, // Existing context (OPT)
+ LPSTR pszTargetName, // Name of target
+ unsigned long fContextReq, // Context Requirements
+ unsigned long Reserved1, // Reserved, MBZ
+ unsigned long TargetDataRep, // Data rep of target
+ PSecBufferDesc pInput, // Input Buffers
+ unsigned long Reserved2, // Reserved, MBZ
+ PCtxtHandle phNewContext, // (out) New Context handle
+ PSecBufferDesc pOutput, // (inout) Output Buffers
+ unsigned long *pfContextAttr, // (out) Context attrs
+ PTimeStamp ptsExpiry // (out) Life span (OPT)
+);
+
+typedef DWORD (WINAPI *initializeSecurityContext_fn)(
+ PCredHandle phCredential, PCtxtHandle phContext, LPSTR pszTargetName, unsigned long fContextReq,
+ unsigned long Reserved1, unsigned long TargetDataRep, PSecBufferDesc pInput, unsigned long Reserved2,
+ PCtxtHandle phNewContext, PSecBufferDesc pOutput, unsigned long *pfContextAttr, PTimeStamp ptsExpiry);
+
+SECURITY_STATUS SEC_ENTRY call_sspi_query_context_attributes(
+ PCtxtHandle phContext, // Context to query
+ unsigned long ulAttribute, // Attribute to query
+ void *pBuffer // Buffer for attributes
+);
+
+typedef DWORD (WINAPI *queryContextAttributes_fn)(
+ PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer);
+
+#endif // SSPI_WINDOWS_H
diff --git a/vendor/gopkg.in/mgo.v2/internal/scram/scram.go b/vendor/gopkg.in/mgo.v2/internal/scram/scram.go
new file mode 100644
index 0000000..80cda91
--- /dev/null
+++ b/vendor/gopkg.in/mgo.v2/internal/scram/scram.go
@@ -0,0 +1,266 @@
+// mgo - MongoDB driver for Go
+//
+// Copyright (c) 2014 - Gustavo Niemeyer <gustavo@niemeyer.net>
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// 2. 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.
+//
+// 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.
+
+// Pacakage scram implements a SCRAM-{SHA-1,etc} client per RFC5802.
+//
+// http://tools.ietf.org/html/rfc5802
+//
+package scram
+
+import (
+ "bytes"
+ "crypto/hmac"
+ "crypto/rand"
+ "encoding/base64"
+ "fmt"
+ "hash"
+ "strconv"
+ "strings"
+)
+
+// Client implements a SCRAM-* client (SCRAM-SHA-1, SCRAM-SHA-256, etc).
+//
+// A Client may be used within a SASL conversation with logic resembling:
+//
+// var in []byte
+// var client = scram.NewClient(sha1.New, user, pass)
+// for client.Step(in) {
+// out := client.Out()
+// // send out to server
+// in := serverOut
+// }
+// if client.Err() != nil {
+// // auth failed
+// }
+//
+type Client struct {
+ newHash func() hash.Hash
+
+ user string
+ pass string
+ step int
+ out bytes.Buffer
+ err error
+
+ clientNonce []byte
+ serverNonce []byte
+ saltedPass []byte
+ authMsg bytes.Buffer
+}
+
+// NewClient returns a new SCRAM-* client with the provided hash algorithm.
+//
+// For SCRAM-SHA-1, for example, use:
+//
+// client := scram.NewClient(sha1.New, user, pass)
+//
+func NewClient(newHash func() hash.Hash, user, pass string) *Client {
+ c := &Client{
+ newHash: newHash,
+ user: user,
+ pass: pass,
+ }
+ c.out.Grow(256)
+ c.authMsg.Grow(256)
+ return c
+}
+
+// Out returns the data to be sent to the server in the current step.
+func (c *Client) Out() []byte {
+ if c.out.Len() == 0 {
+ return nil
+ }
+ return c.out.Bytes()
+}
+
+// Err returns the error that ocurred, or nil if there were no errors.
+func (c *Client) Err() error {
+ return c.err
+}
+
+// SetNonce sets the client nonce to the provided value.
+// If not set, the nonce is generated automatically out of crypto/rand on the first step.
+func (c *Client) SetNonce(nonce []byte) {
+ c.clientNonce = nonce
+}
+
+var escaper = strings.NewReplacer("=", "=3D", ",", "=2C")
+
+// Step processes the incoming data from the server and makes the
+// next round of data for the server available via Client.Out.
+// Step returns false if there are no errors and more data is
+// still expected.
+func (c *Client) Step(in []byte) bool {
+ c.out.Reset()
+ if c.step > 2 || c.err != nil {
+ return false
+ }
+ c.step++
+ switch c.step {
+ case 1:
+ c.err = c.step1(in)
+ case 2:
+ c.err = c.step2(in)
+ case 3:
+ c.err = c.step3(in)
+ }
+ return c.step > 2 || c.err != nil
+}
+
+func (c *Client) step1(in []byte) error {
+ if len(c.clientNonce) == 0 {
+ const nonceLen = 6
+ buf := make([]byte, nonceLen + b64.EncodedLen(nonceLen))
+ if _, err := rand.Read(buf[:nonceLen]); err != nil {
+ return fmt.Errorf("cannot read random SCRAM-SHA-1 nonce from operating system: %v", err)
+ }
+ c.clientNonce = buf[nonceLen:]
+ b64.Encode(c.clientNonce, buf[:nonceLen])
+ }
+ c.authMsg.WriteString("n=")
+ escaper.WriteString(&c.authMsg, c.user)
+ c.authMsg.WriteString(",r=")
+ c.authMsg.Write(c.clientNonce)
+
+ c.out.WriteString("n,,")
+ c.out.Write(c.authMsg.Bytes())
+ return nil
+}
+
+var b64 = base64.StdEncoding
+
+func (c *Client) step2(in []byte) error {
+ c.authMsg.WriteByte(',')
+ c.authMsg.Write(in)
+
+ fields := bytes.Split(in, []byte(","))
+ if len(fields) != 3 {
+ return fmt.Errorf("expected 3 fields in first SCRAM-SHA-1 server message, got %d: %q", len(fields), in)
+ }
+ if !bytes.HasPrefix(fields[0], []byte("r=")) || len(fields[0]) < 2 {
+ return fmt.Errorf("server sent an invalid SCRAM-SHA-1 nonce: %q", fields[0])
+ }
+ if !bytes.HasPrefix(fields[1], []byte("s=")) || len(fields[1]) < 6 {
+ return fmt.Errorf("server sent an invalid SCRAM-SHA-1 salt: %q", fields[1])
+ }
+ if !bytes.HasPrefix(fields[2], []byte("i=")) || len(fields[2]) < 6 {
+ return fmt.Errorf("server sent an invalid SCRAM-SHA-1 iteration count: %q", fields[2])
+ }
+
+ c.serverNonce = fields[0][2:]
+ if !bytes.HasPrefix(c.serverNonce, c.clientNonce) {
+ return fmt.Errorf("server SCRAM-SHA-1 nonce is not prefixed by client nonce: got %q, want %q+\"...\"", c.serverNonce, c.clientNonce)
+ }
+
+ salt := make([]byte, b64.DecodedLen(len(fields[1][2:])))
+ n, err := b64.Decode(salt, fields[1][2:])
+ if err != nil {
+ return fmt.Errorf("cannot decode SCRAM-SHA-1 salt sent by server: %q", fields[1])
+ }
+ salt = salt[:n]
+ iterCount, err := strconv.Atoi(string(fields[2][2:]))
+ if err != nil {
+ return fmt.Errorf("server sent an invalid SCRAM-SHA-1 iteration count: %q", fields[2])
+ }
+ c.saltPassword(salt, iterCount)
+
+ c.authMsg.WriteString(",c=biws,r=")
+ c.authMsg.Write(c.serverNonce)
+
+ c.out.WriteString("c=biws,r=")
+ c.out.Write(c.serverNonce)
+ c.out.WriteString(",p=")
+ c.out.Write(c.clientProof())
+ return nil
+}
+
+func (c *Client) step3(in []byte) error {
+ var isv, ise bool
+ var fields = bytes.Split(in, []byte(","))
+ if len(fields) == 1 {
+ isv = bytes.HasPrefix(fields[0], []byte("v="))
+ ise = bytes.HasPrefix(fields[0], []byte("e="))
+ }
+ if ise {
+ return fmt.Errorf("SCRAM-SHA-1 authentication error: %s", fields[0][2:])
+ } else if !isv {
+ return fmt.Errorf("unsupported SCRAM-SHA-1 final message from server: %q", in)
+ }
+ if !bytes.Equal(c.serverSignature(), fields[0][2:]) {
+ return fmt.Errorf("cannot authenticate SCRAM-SHA-1 server signature: %q", fields[0][2:])
+ }
+ return nil
+}
+
+func (c *Client) saltPassword(salt []byte, iterCount int) {
+ mac := hmac.New(c.newHash, []byte(c.pass))
+ mac.Write(salt)
+ mac.Write([]byte{0, 0, 0, 1})
+ ui := mac.Sum(nil)
+ hi := make([]byte, len(ui))
+ copy(hi, ui)
+ for i := 1; i < iterCount; i++ {
+ mac.Reset()
+ mac.Write(ui)
+ mac.Sum(ui[:0])
+ for j, b := range ui {
+ hi[j] ^= b
+ }
+ }
+ c.saltedPass = hi
+}
+
+func (c *Client) clientProof() []byte {
+ mac := hmac.New(c.newHash, c.saltedPass)
+ mac.Write([]byte("Client Key"))
+ clientKey := mac.Sum(nil)
+ hash := c.newHash()
+ hash.Write(clientKey)
+ storedKey := hash.Sum(nil)
+ mac = hmac.New(c.newHash, storedKey)
+ mac.Write(c.authMsg.Bytes())
+ clientProof := mac.Sum(nil)
+ for i, b := range clientKey {
+ clientProof[i] ^= b
+ }
+ clientProof64 := make([]byte, b64.EncodedLen(len(clientProof)))
+ b64.Encode(clientProof64, clientProof)
+ return clientProof64
+}
+
+func (c *Client) serverSignature() []byte {
+ mac := hmac.New(c.newHash, c.saltedPass)
+ mac.Write([]byte("Server Key"))
+ serverKey := mac.Sum(nil)
+
+ mac = hmac.New(c.newHash, serverKey)
+ mac.Write(c.authMsg.Bytes())
+ serverSignature := mac.Sum(nil)
+
+ encoded := make([]byte, b64.EncodedLen(len(serverSignature)))
+ b64.Encode(encoded, serverSignature)
+ return encoded
+}