update pam lib to address go point issue

This commit is contained in:
Boshi Lian 2018-12-26 21:43:38 +00:00
parent ea9357ff6c
commit f6e64a7538
20 changed files with 906 additions and 511 deletions

65
Gopkg.lock generated
View file

@ -2,120 +2,69 @@
[[projects]]
digest = "1:e692d16fdfbddb94e9e4886aaf6c08bdbae5cb4ac80651445de9181b371c6e46"
name = "github.com/go-sql-driver/mysql"
packages = ["."]
pruneopts = ""
revision = "72cd26f257d44c1114970e19afddcd812016007e"
version = "v1.4.1"
[[projects]]
branch = "master"
digest = "1:ee794fcc4662943ce9c4ad989c6025e40ef53dce5a50527c93c2174489e1e766"
name = "github.com/gokyle/sshkey"
packages = [
".",
"readpass",
]
pruneopts = ""
packages = [".","readpass"]
revision = "d32a9ef172a1ec91efdf3ce26b240c946285bfe7"
[[projects]]
digest = "1:ca5c90960520407749b98c49650f54f5f90a667796e85c5ee1597478f702fb91"
name = "github.com/jessevdk/go-flags"
packages = ["."]
pruneopts = ""
revision = "c6ca198ec95c841fdb89fc0de7496fed11ab854e"
version = "v1.4.0"
[[projects]]
digest = "1:7d4958827c8f2d9d31e24d9a3a52194eb179f77d854692e57954c516ecf76748"
name = "github.com/jinzhu/gorm"
packages = [
".",
"dialects/mysql",
"dialects/postgres",
"dialects/sqlite",
]
pruneopts = ""
packages = [".","dialects/mysql","dialects/postgres","dialects/sqlite"]
revision = "472c70caa40267cb89fd8facb07fe6454b578626"
version = "v1.9.2"
[[projects]]
branch = "master"
digest = "1:d9a7385b84d8187fd94e0357045c6fa1147ca94caa56fdd539336c7c102fc728"
name = "github.com/jinzhu/inflection"
packages = ["."]
pruneopts = ""
revision = "04140366298a54a039076d798123ffa108fff46c"
[[projects]]
digest = "1:29145d7af4adafd72a79df5e41456ac9e232d5a28c1cd4dacf3ff008a217fc10"
name = "github.com/lib/pq"
packages = [
".",
"hstore",
"oid",
]
pruneopts = ""
packages = [".","hstore","oid"]
revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
version = "v1.0.0"
[[projects]]
digest = "1:8bbdb2b3dce59271877770d6fe7dcbb8362438fa7d2e1e1f688e4bf2aac72706"
name = "github.com/mattn/go-sqlite3"
packages = ["."]
pruneopts = ""
revision = "c7c4067b79cc51e6dfdcef5c702e74b1e0fa7c75"
version = "v1.10.0"
[[projects]]
branch = "master"
digest = "1:2463cdbd99f191d5f1040994df41156926ce7b637564b8fb5988729f9bc88eac"
name = "github.com/vvanpo/golang-pam"
name = "github.com/msteinert/pam"
packages = ["."]
pruneopts = ""
revision = "93273af664c1f77cd9ad7e7e10b915503a90c561"
revision = "f4cd9f5e29232537a12db1678f48c702ad6896b7"
[[projects]]
branch = "master"
digest = "1:9ac396eb50b52c1125e696070e1292e7248d62daf126ecf0f749e26333073864"
name = "golang.org/x/crypto"
packages = [
"curve25519",
"ed25519",
"ed25519/internal/edwards25519",
"internal/chacha20",
"poly1305",
"ssh",
"ssh/testdata",
]
pruneopts = ""
packages = ["curve25519","ed25519","ed25519/internal/edwards25519","internal/chacha20","poly1305","ssh","ssh/testdata"]
revision = "a3947c90260b2290d5db1b779520e75f21ad8baf"
source = "https://github.com/tg123/sshpiper.crypto"
[[projects]]
digest = "1:77d3cff3a451d50be4b52db9c7766c0d8570ba47593f0c9dc72173adb208e788"
name = "google.golang.org/appengine"
packages = ["cloudsql"]
pruneopts = ""
revision = "4a4468ece617fc8205e99368fa2200e9d1fad421"
version = "v1.3.0"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/go-sql-driver/mysql",
"github.com/gokyle/sshkey",
"github.com/jessevdk/go-flags",
"github.com/jinzhu/gorm",
"github.com/jinzhu/gorm/dialects/mysql",
"github.com/jinzhu/gorm/dialects/postgres",
"github.com/jinzhu/gorm/dialects/sqlite",
"github.com/vvanpo/golang-pam",
"golang.org/x/crypto/ssh",
"golang.org/x/crypto/ssh/testdata",
]
inputs-digest = "52065920d52958f5461e7df92a92483c9eb78c9bb4b504e0bc82e68e38cfb191"
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -20,11 +20,6 @@
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
branch = "master"
name = "github.com/vvanpo/golang-pam"
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"

View file

@ -5,10 +5,11 @@ package pam
import (
"fmt"
"os"
"errors"
"golang.org/x/crypto/ssh"
pam "github.com/vvanpo/golang-pam"
"github.com/msteinert/pam"
"github.com/tg123/sshpiper/sshpiperd/challenger"
)
@ -21,44 +22,42 @@ func pamChallenger(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChalleng
user := conn.User()
sendQuesttion := func(question string, echo bool) (string, bool) {
sendQuesttion := func(question string, echo bool) (string, error) {
ans, err := client(user, "", []string{question}, []bool{echo})
// TODO lost err
if err != nil {
return "", false
return "", err
}
return ans[0], true
return ans[0], nil
}
sendInstruction := func(instruction string) (string, bool) {
sendInstruction := func(instruction string) (string, error) {
_, err := client(user, instruction, nil, nil)
return "", err == nil
return "", err
}
t, status := pam.Start("sshpiperd", user, pam.ResponseFunc(func(style int, msg string) (string, bool) {
t, err := pam.StartFunc("sshpiperd", user, func(style pam.Style, msg string) (string, error) {
switch style {
case pam.PROMPT_ECHO_OFF:
case pam.PromptEchoOff:
return sendQuesttion(msg, false)
case pam.PROMPT_ECHO_ON:
case pam.PromptEchoOn:
return sendQuesttion(msg, true)
case pam.ERROR_MSG:
case pam.ErrorMsg:
return sendInstruction(fmt.Sprintf("Error: %s", msg))
case pam.TEXT_INFO:
case pam.TextInfo:
return sendInstruction(msg)
}
return "", false
}))
return "", errors.New("Unrecognized message style")
})
if status != pam.SUCCESS {
return false, fmt.Errorf("pam.Start() failed: %s\n", t.Error(status))
if err != nil {
return false, err
}
defer func() { t.End(status) }()
status = t.Authenticate(0)
if status != pam.SUCCESS {
return false, fmt.Errorf("Auth failed: %s\n", t.Error(status))
err = t.Authenticate(0)
if err != nil {
return false, err
}
return true, nil

24
vendor/github.com/msteinert/pam/LICENSE generated vendored Normal file
View file

@ -0,0 +1,24 @@
Copyright 2011, krockot
Copyright 2015, Michael Steinert <mike.steinert@gmail.com>
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.
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 HOLDER 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.

30
vendor/github.com/msteinert/pam/README.md generated vendored Normal file
View file

@ -0,0 +1,30 @@
[![Build Status](https://travis-ci.org/msteinert/pam.svg?branch=master)](https://travis-ci.org/msteinert/pam)
[![GoDoc](https://godoc.org/github.com/msteinert/pam?status.svg)](http://godoc.org/github.com/msteinert/pam)
[![Coverage Status](https://coveralls.io/repos/msteinert/pam/badge.svg?branch=master)](https://coveralls.io/r/msteinert/pam?branch=master)
[![Go Report Card](http://goreportcard.com/badge/msteinert/pam)](http://goreportcard.com/report/msteinert/pam)
# Go PAM
This is a Go wrapper for the PAM application API.
## Testing
To run the full suite, the tests must be run as the root user. To setup your
system for testing, create a user named "test" with the password "secret". For
example:
```
$ sudo useradd test \
-d /tmp/test \
-p '$1$Qd8H95T5$RYSZQeoFbEB.gS19zS99A0' \
-s /bin/false
```
Then execute the tests:
```
$ sudo GOPATH=$GOPATH $(which go) test -v
```
[1]: http://godoc.org/github.com/msteinert/pam
[2]: http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_ADG.html

39
vendor/github.com/msteinert/pam/callback.go generated vendored Normal file
View file

@ -0,0 +1,39 @@
package pam
import "sync"
var cb struct {
sync.Mutex
m map[int]interface{}
c int
}
func init() {
cb.m = make(map[int]interface{})
}
func cbAdd(v interface{}) int {
cb.Lock()
defer cb.Unlock()
cb.c++
cb.m[cb.c] = v
return cb.c
}
func cbGet(c int) interface{} {
cb.Lock()
defer cb.Unlock()
if v, ok := cb.m[c]; ok {
return v
}
panic("Callback pointer not found")
}
func cbDelete(c int) {
cb.Lock()
defer cb.Unlock()
if _, ok := cb.m[c]; !ok {
panic("Callback pointer not found")
}
delete(cb.m, c)
}

33
vendor/github.com/msteinert/pam/callback_test.go generated vendored Normal file
View file

@ -0,0 +1,33 @@
package pam
import (
"reflect"
"testing"
)
func TestCallback_001(t *testing.T) {
c := cbAdd(TestCallback_001)
v := cbGet(c)
if reflect.TypeOf(v) != reflect.TypeOf(TestCallback_001) {
t.Error("Received unexpected value")
}
cbDelete(c)
}
func TestCallback_002(t *testing.T) {
defer func() {
recover()
}()
c := cbAdd(TestCallback_002)
cbGet(c + 1)
t.Error("Expected a panic")
}
func TestCallback_003(t *testing.T) {
defer func() {
recover()
}()
c := cbAdd(TestCallback_003)
cbDelete(c + 1)
t.Error("Expected a panic")
}

53
vendor/github.com/msteinert/pam/example_test.go generated vendored Normal file
View file

@ -0,0 +1,53 @@
package pam_test
import (
"bufio"
"errors"
"fmt"
"log"
"os"
"github.com/bgentry/speakeasy"
"github.com/msteinert/pam"
)
// This example uses whatever default PAM service configuration is available
// on the system, and tries to authenticate any user. This should cause PAM
// to ask its conversation handler for a username and password, in sequence.
//
// This application will handle those requests by displaying the
// PAM-provided prompt and sending back the first line of stdin input
// it can read for each.
//
// Keep in mind that unless run as root (or setuid root), the only
// user's authentication that can succeed is that of the process owner.
func Example_authenticate() {
t, err := pam.StartFunc("", "", func(s pam.Style, msg string) (string, error) {
switch s {
case pam.PromptEchoOff:
return speakeasy.Ask(msg)
case pam.PromptEchoOn:
fmt.Print(msg + " ")
input, err := bufio.NewReader(os.Stdin).ReadString('\n')
if err != nil {
return "", err
}
return input[:len(input)-1], nil
case pam.ErrorMsg:
log.Print(msg)
return "", nil
case pam.TextInfo:
fmt.Println(msg)
return "", nil
}
return "", errors.New("Unrecognized message style")
})
if err != nil {
log.Fatalf("Start: %s", err.Error())
}
err = t.Authenticate(0)
if err != nil {
log.Fatalf("Authenticate: %s", err.Error())
}
fmt.Println("Authentication succeeded!")
}

46
vendor/github.com/msteinert/pam/transaction.c generated vendored Normal file
View file

@ -0,0 +1,46 @@
#include "_cgo_export.h"
#include <security/pam_appl.h>
#include <string.h>
int cb_pam_conv(
int num_msg,
const struct pam_message **msg,
struct pam_response **resp,
void *appdata_ptr)
{
*resp = calloc(num_msg, sizeof **resp);
if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG) {
return PAM_CONV_ERR;
}
if (!*resp) {
return PAM_BUF_ERR;
}
for (size_t i = 0; i < num_msg; ++i) {
struct cbPAMConv_return result = cbPAMConv(
msg[i]->msg_style,
(char *)msg[i]->msg,
(long)appdata_ptr);
if (result.r1 != PAM_SUCCESS) {
goto error;
}
(*resp)[i].resp = result.r0;
}
return PAM_SUCCESS;
error:
for (size_t i = 0; i < num_msg; ++i) {
if ((*resp)[i].resp) {
memset((*resp)[i].resp, 0, strlen((*resp)[i].resp));
free((*resp)[i].resp);
}
}
memset(*resp, 0, num_msg * sizeof *resp);
free(*resp);
*resp = NULL;
return PAM_CONV_ERR;
}
void init_pam_conv(struct pam_conv *conv, long c)
{
conv->conv = cb_pam_conv;
conv->appdata_ptr = (void *)c;
}

306
vendor/github.com/msteinert/pam/transaction.go generated vendored Normal file
View file

@ -0,0 +1,306 @@
// Package pam provides a wrapper for the PAM application API.
package pam
//#include <security/pam_appl.h>
//#include <stdlib.h>
//#cgo CFLAGS: -Wall -std=c99
//#cgo LDFLAGS: -lpam
//void init_pam_conv(struct pam_conv *conv, long c);
import "C"
import (
"runtime"
"strings"
"unsafe"
)
// Style is the type of message that the conversation handler should display.
type Style int
// Coversation handler style types.
const (
// PromptEchoOff indicates the conversation handler should obtain a
// string without echoing any text.
PromptEchoOff Style = C.PAM_PROMPT_ECHO_OFF
// PromptEchoOn indicates the conversation handler should obtain a
// string while echoing text.
PromptEchoOn = C.PAM_PROMPT_ECHO_ON
// ErrorMsg indicates the conversation handler should display an
// error message.
ErrorMsg = C.PAM_ERROR_MSG
// TextInfo indicates the conversation handler should display some
// text.
TextInfo = C.PAM_TEXT_INFO
)
// ConversationHandler is an interface for objects that can be used as
// conversation callbacks during PAM authentication.
type ConversationHandler interface {
// RespondPAM receives a message style and a message string. If the
// message Style is PromptEchoOff or PromptEchoOn then the function
// should return a response string.
RespondPAM(Style, string) (string, error)
}
// ConversationFunc is an adapter to allow the use of ordinary functions as
// conversation callbacks.
type ConversationFunc func(Style, string) (string, error)
// RespondPAM is a conversation callback adapter.
func (f ConversationFunc) RespondPAM(s Style, msg string) (string, error) {
return f(s, msg)
}
// cbPAMConv is a wrapper for the conversation callback function.
//export cbPAMConv
func cbPAMConv(s C.int, msg *C.char, c int) (*C.char, C.int) {
var r string
var err error
v := cbGet(c)
switch cb := v.(type) {
case ConversationHandler:
r, err = cb.RespondPAM(Style(s), C.GoString(msg))
}
if err != nil {
return nil, C.PAM_CONV_ERR
}
return C.CString(r), C.PAM_SUCCESS
}
// Transaction is the application's handle for a PAM transaction.
type Transaction struct {
handle *C.pam_handle_t
conv *C.struct_pam_conv
status C.int
c int
}
// transactionFinalizer cleans up the PAM handle and deletes the callback
// function.
func transactionFinalizer(t *Transaction) {
C.pam_end(t.handle, t.status)
cbDelete(t.c)
}
// Start initiates a new PAM transaction. Service is treated identically to
// how pam_start treats it internally.
//
// All application calls to PAM begin with Start (or StartFunc). The returned
// transaction provides an interface to the remainder of the API.
func Start(service, user string, handler ConversationHandler) (*Transaction, error) {
t := &Transaction{
conv: &C.struct_pam_conv{},
c: cbAdd(handler),
}
C.init_pam_conv(t.conv, C.long(t.c))
runtime.SetFinalizer(t, transactionFinalizer)
s := C.CString(service)
defer C.free(unsafe.Pointer(s))
var u *C.char
if len(user) != 0 {
u = C.CString(user)
defer C.free(unsafe.Pointer(u))
}
t.status = C.pam_start(s, u, t.conv, &t.handle)
if t.status != C.PAM_SUCCESS {
return nil, t
}
return t, nil
}
// StartFunc registers the handler func as a conversation handler.
func StartFunc(service, user string, handler func(Style, string) (string, error)) (*Transaction, error) {
return Start(service, user, ConversationFunc(handler))
}
func (t *Transaction) Error() string {
return C.GoString(C.pam_strerror(t.handle, C.int(t.status)))
}
// Item is a an PAM information type.
type Item int
// PAM Item types.
const (
// Service is the name which identifies the PAM stack.
Service Item = C.PAM_SERVICE
// User identifies the username identity used by a service.
User = C.PAM_USER
// Tty is the terminal name.
Tty = C.PAM_TTY
// Rhost is the requesting host name.
Rhost = C.PAM_RHOST
// Authtok is the currently active authentication token.
Authtok = C.PAM_AUTHTOK
// Oldauthtok is the old authentication token.
Oldauthtok = C.PAM_OLDAUTHTOK
// Ruser is the requesting user name.
Ruser = C.PAM_RUSER
// UserPrompt is the string use to prompt for a username.
UserPrompt = C.PAM_USER_PROMPT
)
// SetItem sets a PAM information item.
func (t *Transaction) SetItem(i Item, item string) error {
cs := unsafe.Pointer(C.CString(item))
defer C.free(cs)
t.status = C.pam_set_item(t.handle, C.int(i), cs)
if t.status != C.PAM_SUCCESS {
return t
}
return nil
}
// GetItem retrieves a PAM information item.
func (t *Transaction) GetItem(i Item) (string, error) {
var s unsafe.Pointer
t.status = C.pam_get_item(t.handle, C.int(i), &s)
if t.status != C.PAM_SUCCESS {
return "", t
}
return C.GoString((*C.char)(s)), nil
}
// Flags are inputs to various PAM functions than be combined with a bitwise
// or. Refer to the official PAM documentation for which flags are accepted
// by which functions.
type Flags int
// PAM Flag types.
const (
// Silent indicates that no messages should be emitted.
Silent Flags = C.PAM_SILENT
// DisallowNullAuthtok indicates that authorization should fail
// if the user does not have a registered authentication token.
DisallowNullAuthtok = C.PAM_DISALLOW_NULL_AUTHTOK
// EstablishCred indicates that credentials should be established
// for the user.
EstablishCred = C.PAM_ESTABLISH_CRED
// DeleteCred inidicates that credentials should be deleted.
DeleteCred = C.PAM_DELETE_CRED
// ReinitializeCred indicates that credentials should be fully
// reinitialized.
ReinitializeCred = C.PAM_REINITIALIZE_CRED
// RefreshCred indicates that the lifetime of existing credentials
// should be extended.
RefreshCred = C.PAM_REFRESH_CRED
// ChangeExpiredAuthtok indicates that the authentication token
// should be changed if it has expired.
ChangeExpiredAuthtok = C.PAM_CHANGE_EXPIRED_AUTHTOK
)
// Authenticate is used to authenticate the user.
//
// Valid flags: Silent, DisallowNullAuthtok
func (t *Transaction) Authenticate(f Flags) error {
t.status = C.pam_authenticate(t.handle, C.int(f))
if t.status != C.PAM_SUCCESS {
return t
}
return nil
}
// SetCred is used to establish, maintain and delete the credentials of a
// user.
//
// Valid flags: EstablishCred, DeleteCred, ReinitializeCred, RefreshCred
func (t *Transaction) SetCred(f Flags) error {
t.status = C.pam_setcred(t.handle, C.int(f))
if t.status != C.PAM_SUCCESS {
return t
}
return nil
}
// AcctMgmt is used to determine if the user's account is valid.
//
// Valid flags: Silent, DisallowNullAuthtok
func (t *Transaction) AcctMgmt(f Flags) error {
t.status = C.pam_acct_mgmt(t.handle, C.int(f))
if t.status != C.PAM_SUCCESS {
return t
}
return nil
}
// ChangeAuthTok is used to change the authentication token.
//
// Valid flags: Silent, ChangeExpiredAuthtok
func (t *Transaction) ChangeAuthTok(f Flags) error {
t.status = C.pam_chauthtok(t.handle, C.int(f))
if t.status != C.PAM_SUCCESS {
return t
}
return nil
}
// OpenSession sets up a user session for an authenticated user.
//
// Valid flags: Slient
func (t *Transaction) OpenSession(f Flags) error {
t.status = C.pam_open_session(t.handle, C.int(f))
if t.status != C.PAM_SUCCESS {
return t
}
return nil
}
// CloseSession closes a previously opened session.
//
// Valid flags: Silent
func (t *Transaction) CloseSession(f Flags) error {
t.status = C.pam_close_session(t.handle, C.int(f))
if t.status != C.PAM_SUCCESS {
return t
}
return nil
}
// PutEnv adds or changes the value of PAM environment variables.
//
// NAME=value will set a variable to a value.
// NAME= will set a variable to an empty value.
// NAME (without an "=") will delete a variable.
func (t *Transaction) PutEnv(nameval string) error {
cs := C.CString(nameval)
defer C.free(unsafe.Pointer(cs))
t.status = C.pam_putenv(t.handle, cs)
if t.status != C.PAM_SUCCESS {
return t
}
return nil
}
// GetEnv is used to retrieve a PAM environment variable.
func (t *Transaction) GetEnv(name string) string {
cs := C.CString(name)
defer C.free(unsafe.Pointer(cs))
value := C.pam_getenv(t.handle, cs)
if value == nil {
return ""
}
return C.GoString(value)
}
func next(p **C.char) **C.char {
return (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(p)))
}
// GetEnvList returns a copy of the PAM environment as a map.
func (t *Transaction) GetEnvList() (map[string]string, error) {
env := make(map[string]string)
p := C.pam_getenvlist(t.handle)
if p == nil {
t.status = C.PAM_BUF_ERR
return nil, t
}
for q := p; *q != nil; q = next(q) {
chunks := strings.SplitN(C.GoString(*q), "=", 2)
if len(chunks) == 2 {
env[chunks[0]] = chunks[1]
}
C.free(unsafe.Pointer(*q))
}
C.free(unsafe.Pointer(p))
return env, nil
}

349
vendor/github.com/msteinert/pam/transaction_test.go generated vendored Normal file
View file

@ -0,0 +1,349 @@
package pam
import (
"errors"
"os/user"
"runtime"
"testing"
)
func TestPAM_001(t *testing.T) {
u, _ := user.Current()
if u.Uid != "0" {
t.Skip("run this test as root")
}
p := "secret"
tx, err := StartFunc("", "test", func(s Style, msg string) (string, error) {
return p, nil
})
if err != nil {
t.Fatalf("start #error: %v", err)
}
err = tx.Authenticate(0)
if err != nil {
t.Fatalf("authenticate #error: %v", err)
}
err = tx.AcctMgmt(Silent)
if err != nil {
t.Fatalf("acct_mgmt #error: %v", err)
}
err = tx.SetCred(Silent | EstablishCred)
if err != nil {
t.Fatalf("setcred #error: %v", err)
}
runtime.GC()
}
func TestPAM_002(t *testing.T) {
u, _ := user.Current()
if u.Uid != "0" {
t.Skip("run this test as root")
}
tx, err := StartFunc("", "", func(s Style, msg string) (string, error) {
switch s {
case PromptEchoOn:
return "test", nil
case PromptEchoOff:
return "secret", nil
}
return "", errors.New("unexpected")
})
if err != nil {
t.Fatalf("start #error: %v", err)
}
err = tx.Authenticate(0)
if err != nil {
t.Fatalf("authenticate #error: %v", err)
}
runtime.GC()
}
type Credentials struct {
User string
Password string
}
func (c Credentials) RespondPAM(s Style, msg string) (string, error) {
switch s {
case PromptEchoOn:
return c.User, nil
case PromptEchoOff:
return c.Password, nil
}
return "", errors.New("unexpected")
}
func TestPAM_003(t *testing.T) {
u, _ := user.Current()
if u.Uid != "0" {
t.Skip("run this test as root")
}
c := Credentials{
User: "test",
Password: "secret",
}
tx, err := Start("", "", c)
if err != nil {
t.Fatalf("start #error: %v", err)
}
err = tx.Authenticate(0)
if err != nil {
t.Fatalf("authenticate #error: %v", err)
}
runtime.GC()
}
func TestPAM_004(t *testing.T) {
u, _ := user.Current()
if u.Uid != "0" {
t.Skip("run this test as root")
}
c := Credentials{
Password: "secret",
}
tx, err := Start("", "test", c)
if err != nil {
t.Fatalf("start #error: %v", err)
}
err = tx.Authenticate(0)
if err != nil {
t.Fatalf("authenticate #error: %v", err)
}
runtime.GC()
}
func TestPAM_005(t *testing.T) {
u, _ := user.Current()
if u.Uid != "0" {
t.Skip("run this test as root")
}
tx, err := StartFunc("passwd", "test", func(s Style, msg string) (string, error) {
return "secret", nil
})
if err != nil {
t.Fatalf("start #error: %v", err)
}
err = tx.ChangeAuthTok(Silent)
if err != nil {
t.Fatalf("chauthtok #error: %v", err)
}
runtime.GC()
}
func TestPAM_006(t *testing.T) {
u, _ := user.Current()
if u.Uid != "0" {
t.Skip("run this test as root")
}
tx, err := StartFunc("passwd", u.Username, func(s Style, msg string) (string, error) {
return "secret", nil
})
if err != nil {
t.Fatalf("start #error: %v", err)
}
err = tx.OpenSession(Silent)
if err != nil {
t.Fatalf("open_session #error: %v", err)
}
err = tx.CloseSession(Silent)
if err != nil {
t.Fatalf("close_session #error: %v", err)
}
runtime.GC()
}
func TestPAM_007(t *testing.T) {
u, _ := user.Current()
if u.Uid != "0" {
t.Skip("run this test as root")
}
tx, err := StartFunc("", "test", func(s Style, msg string) (string, error) {
return "", errors.New("Sorry, it didn't work")
})
if err != nil {
t.Fatalf("start #error: %v", err)
}
err = tx.Authenticate(0)
if err == nil {
t.Fatalf("authenticate #expected an error")
}
s := err.Error()
if len(s) == 0 {
t.Fatalf("error #expected an error message")
}
runtime.GC()
}
func TestItem(t *testing.T) {
tx, err := StartFunc("passwd", "test", func(s Style, msg string) (string, error) {
return "", nil
})
s, err := tx.GetItem(Service)
if err != nil {
t.Fatalf("getitem #error: %v", err)
}
if s != "passwd" {
t.Fatalf("getitem #error: expected passwd, got %v", s)
}
s, err = tx.GetItem(User)
if err != nil {
t.Fatalf("getitem #error: %v", err)
}
if s != "test" {
t.Fatalf("getitem #error: expected test, got %v", s)
}
err = tx.SetItem(User, "root")
if err != nil {
t.Fatalf("setitem #error: %v", err)
}
s, err = tx.GetItem(User)
if err != nil {
t.Fatalf("getitem #error: %v", err)
}
if s != "root" {
t.Fatalf("getitem #error: expected root, got %v", s)
}
runtime.GC()
}
func TestEnv(t *testing.T) {
tx, err := StartFunc("", "", func(s Style, msg string) (string, error) {
return "", nil
})
if err != nil {
t.Fatalf("start #error: %v", err)
}
m, err := tx.GetEnvList()
if err != nil {
t.Fatalf("getenvlist #error: %v", err)
}
n := len(m)
if n != 0 {
t.Fatalf("putenv #error: expected 0 items, got %v", n)
}
vals := []string{
"VAL1=1",
"VAL2=2",
"VAL3=3",
}
for _, s := range vals {
err = tx.PutEnv(s)
if err != nil {
t.Fatalf("putenv #error: %v", err)
}
}
s := tx.GetEnv("VAL0")
if s != "" {
t.Fatalf("getenv #error: expected \"\", got %v", s)
}
s = tx.GetEnv("VAL1")
if s != "1" {
t.Fatalf("getenv #error: expected 1, got %v", s)
}
s = tx.GetEnv("VAL2")
if s != "2" {
t.Fatalf("getenv #error: expected 2, got %v", s)
}
s = tx.GetEnv("VAL3")
if s != "3" {
t.Fatalf("getenv #error: expected 3, got %v", s)
}
m, err = tx.GetEnvList()
if err != nil {
t.Fatalf("getenvlist #error: %v", err)
}
n = len(m)
if n != 3 {
t.Fatalf("getenvlist #error: expected 3 items, got %v", n)
}
if m["VAL1"] != "1" {
t.Fatalf("getenvlist #error: expected 1, got %v", m["VAL1"])
}
if m["VAL2"] != "2" {
t.Fatalf("getenvlist #error: expected 2, got %v", m["VAL1"])
}
if m["VAL3"] != "3" {
t.Fatalf("getenvlist #error: expected 3, got %v", m["VAL1"])
}
runtime.GC()
}
func TestFailure_001(t *testing.T) {
tx := Transaction{}
_, err := tx.GetEnvList()
if err == nil {
t.Fatalf("getenvlist #expected an error")
}
}
func TestFailure_002(t *testing.T) {
tx := Transaction{}
err := tx.PutEnv("")
if err == nil {
t.Fatalf("getenvlist #expected an error")
}
}
func TestFailure_003(t *testing.T) {
tx := Transaction{}
err := tx.CloseSession(0)
if err == nil {
t.Fatalf("getenvlist #expected an error")
}
}
func TestFailure_004(t *testing.T) {
tx := Transaction{}
err := tx.OpenSession(0)
if err == nil {
t.Fatalf("getenvlist #expected an error")
}
}
func TestFailure_005(t *testing.T) {
tx := Transaction{}
err := tx.ChangeAuthTok(0)
if err == nil {
t.Fatalf("getenvlist #expected an error")
}
}
func TestFailure_006(t *testing.T) {
tx := Transaction{}
err := tx.AcctMgmt(0)
if err == nil {
t.Fatalf("getenvlist #expected an error")
}
}
func TestFailure_007(t *testing.T) {
tx := Transaction{}
err := tx.SetCred(0)
if err == nil {
t.Fatalf("getenvlist #expected an error")
}
}
func TestFailure_008(t *testing.T) {
tx := Transaction{}
err := tx.SetItem(User, "test")
if err == nil {
t.Fatalf("getenvlist #expected an error")
}
}
func TestFailure_009(t *testing.T) {
tx := Transaction{}
_, err := tx.GetItem(User)
if err == nil {
t.Fatalf("getenvlist #expected an error")
}
}

View file

@ -1,67 +0,0 @@
#include <security/pam_types.h>
#include <security/pam_appl.h>
#include <stdlib.h>
#include <string.h>
#include "_cgo_export.h"
/* Simplification of pam_get_item to remove type ambiguity. Will never
be called (promise) with a type that returns anything other than a string */
get_item_result pam_get_item_string(pam_handle_t *handle, int type) {
get_item_result result;
result.status = pam_get_item(handle, type, (const void **)&result.str);
return result;
}
/* The universal conversation callback for gopam transactions. appdata_ptr
is always taken as a raw pointer to a Go-side pam.conversation object.
In order to avoid nightmareish unsafe pointer math all over the Go
implementation, this universal callback deals with memory allocation of
response buffers, as well as unpacking and repackaging incoming messages
and responses, calling a Go-side callback that handles each one on an
individual basis. */
int gopam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
int i, ok = 1;
struct pam_response *responses = (struct pam_response*)malloc(sizeof(struct pam_response) * num_msg);
memset(responses, 0, sizeof(struct pam_response) * num_msg);
for(i = 0; i < num_msg; ++i) {
const struct pam_message *m = msg[i];
struct goPAMConv_return result = goPAMConv(m->msg_style, (char*)m->msg, appdata_ptr);
if(result.r1 == PAM_SUCCESS)
responses[i].resp = result.r0;
else {
ok = 0;
break;
}
}
if(ok) {
*resp = responses;
return PAM_SUCCESS;
}
/* In the case of failure PAM will never see these responses. The
resp strings that have been allocated by Go-side C.CString calls
must be freed lest we leak them. */
for(i = 0; i < num_msg; ++i)
if(responses[i].resp != NULL)
free(responses[i].resp);
free(responses);
return PAM_CONV_ERR;
}
/* This allocates a new pam_conv struct and fills in its fields:
The conv function pointer always points to the universal gopam_conv.
The appdata_ptr will be set to the incoming void* argument, which
is always a Go-side *pam.conversation whose handler was given
to pam.Start(). */
struct pam_conv* make_gopam_conv(void *goconv)
{
struct pam_conv* conv = (struct pam_conv*)malloc(sizeof(struct pam_conv));
conv->conv = gopam_conv;
conv->appdata_ptr = goconv;
return conv;
}

View file

@ -1,11 +0,0 @@
#include <security/pam_appl.h>
#include <stdlib.h>
typedef struct {
const char *str;
int status;
} get_item_result;
get_item_result pam_get_item_string(pam_handle_t *handle, int type);
struct pam_conv* make_gopam_conv(void *goconv);

View file

@ -1,197 +0,0 @@
// Package pam provides a wrapper for the application layer of the
// Pluggable Authentication Modules library.
package pam
import (
//#include "golang-pam.h"
//#cgo LDFLAGS: -lpam
"C"
"unsafe"
"strings"
)
// Objects implementing the ConversationHandler interface can
// be registered as conversation callbacks to be used during
// PAM authentication. RespondPAM receives a message style
// (one of PROMPT_ECHO_OFF, PROMPT_ECHO_ON, ERROR_MSG, or
// TEXT_INFO) and a message string. It is expected to return
// a response string and a bool indicating success or failure.
type ConversationHandler interface {
RespondPAM(msg_style int, msg string) (string,bool)
}
// ResponseFunc is an adapter to allow the use of ordinary
// functions as conversation callbacks. ResponseFunc(f) is
// a ConversationHandler that calls f, where f must have
// the signature func(int,string)(string,bool).
type ResponseFunc func(int,string) (string,bool)
func (f ResponseFunc) RespondPAM(style int, msg string) (string,bool) {
return f(style,msg)
}
// Internal conversation structure
type conversation struct {
handler ConversationHandler
cconv *C.struct_pam_conv
}
// Cosntructs a new conversation object with a given handler and a newly
// allocated pam_conv struct that uses this object as its appdata_ptr
func newConversation(handler ConversationHandler) *conversation {
conv := &conversation{}
conv.handler = handler
conv.cconv = C.make_gopam_conv(unsafe.Pointer(conv))
return conv
}
//export goPAMConv
// Go-side function for processing a single conversational message. Ultimately
// this calls the associated ConversationHandler's ResponsePAM callback with data
// coming in from a C-side call.
func goPAMConv(msg_style C.int, msg *C.char, appdata unsafe.Pointer) (*C.char,int) {
conv := (*conversation)(appdata)
resp,ok := conv.handler.RespondPAM(int(msg_style), C.GoString(msg))
if ok {
return C.CString(resp),SUCCESS
}
return nil,CONV_ERR
}
// Transaction is the application's handle for a single PAM transaction.
type Transaction struct {
handle *C.pam_handle_t
conv *conversation
}
// Start initiates a new PAM transaction. serviceName is treated identically
// to how pam_start internally treats it. The same applies to user, except that
// the empty string is passed to PAM as nil; therefore the empty string should be
// used to signal that no username is being provided.
//
// All application calls to PAM begin with Start(). The returned *Transaction
// provides an interface to the remainder of the API.
//
// The returned status int may be ABORT, BUF_ERR, SUCCESS, or SYSTEM_ERR, as per
// the official PAM documentation.
func Start(serviceName, user string, handler ConversationHandler) (*Transaction,int) {
t := &Transaction{}
t.conv = newConversation(handler)
var status C.int
if len(user) == 0 {
status = C.pam_start(C.CString(serviceName), nil, t.conv.cconv, &t.handle)
} else {
status = C.pam_start(C.CString(serviceName), C.CString(user), t.conv.cconv, &t.handle)
}
if status != SUCCESS {
C.free(unsafe.Pointer(t.conv.cconv))
return nil,int(status)
}
return t, int(status)
}
// Ends a PAM transaction. From Linux-PAM documentation: "The [status] argument
// should be set to the value returned by the last PAM library call."
//
// This may return SUCCESS, or SYSTEM_ERR.
//
// This *must* be called on any Transaction successfully returned by Start() or
// you will leak memory.
func (t *Transaction) End(status int) {
C.pam_end(t.handle, C.int(status))
C.free(unsafe.Pointer(t.conv.cconv))
}
// Sets a PAM informational item. Legal values of itemType are listed here (excluding Linux extensions):
//
// http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/adg-interface-by-app-expected.html#adg-pam_set_item
//
// the CONV item type is also not supported in order to simplify the Go API (and due to
// the fact that it is completely unnecessary).
func (t *Transaction) SetItem(itemType int, item string) int {
if itemType == CONV { return BAD_ITEM }
cs := unsafe.Pointer(C.CString(item))
defer C.free(cs)
return int(C.pam_set_item(t.handle, C.int(itemType), cs))
}
// Gets a PAM item. Legal values of itemType are as specified by the documentation of SetItem.
func (t *Transaction) GetItem(itemType int) (string,int) {
if itemType == CONV { return "",BAD_ITEM }
result := C.pam_get_item_string(t.handle, C.int(itemType))
return C.GoString(result.str),int(result.status)
}
// Error returns a PAM error string from a PAM error code
func (t *Transaction) Error(errnum int) string {
return C.GoString(C.pam_strerror(t.handle, C.int(errnum)))
}
// pam_authenticate
func (t *Transaction) Authenticate(flags int) int {
return int(C.pam_authenticate(t.handle, C.int(flags)))
}
// pam_setcred
func (t* Transaction) SetCred(flags int) int {
return int(C.pam_setcred(t.handle, C.int(flags)))
}
// pam_acctmgmt
func (t* Transaction) AcctMgmt(flags int) int {
return int(C.pam_acct_mgmt(t.handle, C.int(flags)))
}
// pam_chauthtok
func (t* Transaction) ChangeAuthTok(flags int) int {
return int(C.pam_chauthtok(t.handle, C.int(flags)))
}
// pam_open_session
func (t* Transaction) OpenSession(flags int) int {
return int(C.pam_open_session(t.handle, C.int(flags)))
}
// pam_close_session
func (t* Transaction) CloseSession(flags int) int {
return int(C.pam_close_session(t.handle, C.int(flags)))
}
// pam_putenv
func (t* Transaction) PutEnv(nameval string) int {
cs := C.CString(nameval)
defer C.free(unsafe.Pointer(cs))
return int(C.pam_putenv(t.handle, cs))
}
// pam_getenv. Returns an additional argument indicating
// the actual existence of the given environment variable.
func (t* Transaction) GetEnv(name string) (string,bool) {
cs := C.CString(name)
defer C.free(unsafe.Pointer(cs))
value := C.pam_getenv(t.handle, cs)
if value != nil {
return C.GoString(value),true
}
return "",false
}
// GetEnvList internally calls pam_getenvlist and then uses some very
// dangerous code to pull out the returned environment data and mash
// it into a map[string]string. This call may be safe, but it hasn't
// been tested on enough platforms/architectures/PAM-implementations to
// be sure.
func (t* Transaction) GetEnvList() map[string]string {
env := make(map[string]string)
list := (uintptr)(unsafe.Pointer(C.pam_getenvlist(t.handle)))
for *(*uintptr)(unsafe.Pointer(list)) != 0 {
entry := *(*uintptr)(unsafe.Pointer(list))
nameval := C.GoString((*C.char)(unsafe.Pointer(entry)))
chunks := strings.SplitN(nameval, "=", 2)
env[chunks[0]] = chunks[1]
list += (uintptr)(unsafe.Sizeof(list))
}
return env
}

View file

@ -1,90 +0,0 @@
#include <security/pam_appl.h>
enum {
$SUCCESS = PAM_SUCCESS,
$OPEN_ERR = PAM_OPEN_ERR,
$SYMBOL_ERR = PAM_SYMBOL_ERR,
$SERVICE_ERR = PAM_SERVICE_ERR,
$SYSTEM_ERR = PAM_SYSTEM_ERR,
$BUF_ERR = PAM_BUF_ERR,
$PERM_DENIED = PAM_PERM_DENIED,
$AUTH_ERR = PAM_AUTH_ERR,
$CRED_INSUFFICIENT = PAM_CRED_INSUFFICIENT,
$AUTHINFO_UNAVAIL = PAM_AUTHINFO_UNAVAIL,
$USER_UNKNOWN = PAM_USER_UNKNOWN,
$MAXTRIES = PAM_MAXTRIES,
$NEW_AUTHOTK_REQD = PAM_NEW_AUTHTOK_REQD,
$ACCT_EXPIRED = PAM_ACCT_EXPIRED,
$SESSION_ERR = PAM_SESSION_ERR,
$CRED_UNAVAIL = PAM_CRED_UNAVAIL,
$CRED_EXPIRED = PAM_CRED_EXPIRED,
$CRED_ERR = PAM_CRED_ERR,
$NO_MODULE_DATA = PAM_NO_MODULE_DATA,
$CONV_ERR = PAM_CONV_ERR,
$AUTHTOK_ERR = PAM_AUTHTOK_ERR,
$AUTHTOK_RECOVERY_ERR = PAM_AUTHTOK_RECOVERY_ERR,
$AUTHTOK_LOCK_BUSY = PAM_AUTHTOK_LOCK_BUSY,
$AUTHTOK_DISABLE_AGING = PAM_AUTHTOK_DISABLE_AGING,
$TRY_AGAIN = PAM_TRY_AGAIN,
$IGNORE = PAM_IGNORE,
$ABORT = PAM_ABORT,
$AUTHTOK_EXPIRED = PAM_AUTHTOK_EXPIRED,
$MODULE_UNKNOWN = PAM_MODULE_UNKNOWN,
#if !defined(PAM_BAD_ITEM)
$BAD_ITEM = PAM_SYMBOL_ERR,
#else
$BAD_ITEM = PAM_BAD_ITEM,
#endif
#if !defined(PAM_CONV_AGAIN)
$CONV_AGAIN = PAM_SYMBOL_ERR,
#else
$CONV_AGAIN = PAM_CONV_AGAIN,
#endif
#if !defined(PAM_INCOMPLETE)
$INCOMPLETE = PAM_SYMBOL_ERR
#else
$INCOMPLETE = PAM_INCOMPLETE
#endif
};
enum {
$SILENT = PAM_SILENT,
$DISALLOW_NULL_AUTHTOK = PAM_DISALLOW_NULL_AUTHTOK,
$ESTABLISH_CRED = PAM_ESTABLISH_CRED,
$DELETE_CRED = PAM_DELETE_CRED,
$REINITIALIZE_CRED = PAM_REINITIALIZE_CRED,
$REFRESH_CRED = PAM_REFRESH_CRED,
$CHANGE_EXPIRED_AUTHTOK = PAM_CHANGE_EXPIRED_AUTHTOK
};
enum {
$SERVICE = PAM_SERVICE,
$USER = PAM_USER,
$TTY = PAM_TTY,
$RHOST = PAM_RHOST,
$CONV = PAM_CONV,
$AUTHTOK = PAM_AUTHTOK,
$OLDAUTHTOK = PAM_OLDAUTHTOK,
$RUSER = PAM_RUSER,
$USER_PROMPT = PAM_USER_PROMPT,
/* Linux-PAM extensions. Leaving these out, for now...
$FAIL_DELAY = PAM_FAIL_DELAY,
$XDISPLAY = PAM_XDISPLAY,
$XAUTHDATA = PAM_XAUTHDATA,
$AUTHTOK_TYPE = PAM_AUTHTOK_TYPE
*/
};
enum {
$PROMPT_ECHO_OFF = PAM_PROMPT_ECHO_OFF,
$PROMPT_ECHO_ON = PAM_PROMPT_ECHO_ON,
$ERROR_MSG = PAM_ERROR_MSG,
$TEXT_INFO = PAM_TEXT_INFO
};

View file

@ -1,63 +0,0 @@
// godefs -g pam pamdefs.c
// MACHINE GENERATED - DO NOT EDIT.
package pam
// Constants
const (
SUCCESS = 0
OPEN_ERR = 0x1
SYMBOL_ERR = 0x2
SERVICE_ERR = 0x3
SYSTEM_ERR = 0x4
BUF_ERR = 0x5
PERM_DENIED = 0x6
AUTH_ERR = 0x7
CRED_INSUFFICIENT = 0x8
AUTHINFO_UNAVAIL = 0x9
USER_UNKNOWN = 0xa
MAXTRIES = 0xb
NEW_AUTHOTK_REQD = 0xc
ACCT_EXPIRED = 0xd
SESSION_ERR = 0xe
CRED_UNAVAIL = 0xf
CRED_EXPIRED = 0x10
CRED_ERR = 0x11
NO_MODULE_DATA = 0x12
CONV_ERR = 0x13
AUTHTOK_ERR = 0x14
AUTHTOK_RECOVERY_ERR = 0x15
AUTHTOK_LOCK_BUSY = 0x16
AUTHTOK_DISABLE_AGING = 0x17
TRY_AGAIN = 0x18
IGNORE = 0x19
ABORT = 0x1a
AUTHTOK_EXPIRED = 0x1b
MODULE_UNKNOWN = 0x1c
BAD_ITEM = 0x1d
CONV_AGAIN = 0x1e
INCOMPLETE = 0x1f
SILENT = 0x8000
DISALLOW_NULL_AUTHTOK = 0x1
ESTABLISH_CRED = 0x2
DELETE_CRED = 0x4
REINITIALIZE_CRED = 0x8
REFRESH_CRED = 0x10
CHANGE_EXPIRED_AUTHTOK = 0x20
SERVICE = 0x1
USER = 0x2
TTY = 0x3
RHOST = 0x4
CONV = 0x5
AUTHTOK = 0x6
OLDAUTHTOK = 0x7
RUSER = 0x8
USER_PROMPT = 0x9
PROMPT_ECHO_OFF = 0x1
PROMPT_ECHO_ON = 0x2
ERROR_MSG = 0x3
TEXT_INFO = 0x4
)
// Types

0
vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto generated vendored Normal file → Executable file
View file

0
vendor/google.golang.org/appengine/internal/regen.sh generated vendored Normal file → Executable file
View file

0
vendor/google.golang.org/appengine/travis_install.sh generated vendored Normal file → Executable file
View file

0
vendor/google.golang.org/appengine/travis_test.sh generated vendored Normal file → Executable file
View file