update pam lib to address go point issue
This commit is contained in:
parent
ea9357ff6c
commit
f6e64a7538
20 changed files with 906 additions and 511 deletions
65
Gopkg.lock
generated
65
Gopkg.lock
generated
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
24
vendor/github.com/msteinert/pam/LICENSE
generated
vendored
Normal 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
30
vendor/github.com/msteinert/pam/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
[](https://travis-ci.org/msteinert/pam)
|
||||
[](http://godoc.org/github.com/msteinert/pam)
|
||||
[](https://coveralls.io/r/msteinert/pam?branch=master)
|
||||
[](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
39
vendor/github.com/msteinert/pam/callback.go
generated
vendored
Normal 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
33
vendor/github.com/msteinert/pam/callback_test.go
generated
vendored
Normal 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
53
vendor/github.com/msteinert/pam/example_test.go
generated
vendored
Normal 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
46
vendor/github.com/msteinert/pam/transaction.c
generated
vendored
Normal 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
306
vendor/github.com/msteinert/pam/transaction.go
generated
vendored
Normal 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
349
vendor/github.com/msteinert/pam/transaction_test.go
generated
vendored
Normal 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")
|
||||
}
|
||||
}
|
||||
67
vendor/github.com/vvanpo/golang-pam/golang-pam.c
generated
vendored
67
vendor/github.com/vvanpo/golang-pam/golang-pam.c
generated
vendored
|
|
@ -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;
|
||||
}
|
||||
|
||||
11
vendor/github.com/vvanpo/golang-pam/golang-pam.h
generated
vendored
11
vendor/github.com/vvanpo/golang-pam/golang-pam.h
generated
vendored
|
|
@ -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);
|
||||
|
||||
197
vendor/github.com/vvanpo/golang-pam/pam.go
generated
vendored
197
vendor/github.com/vvanpo/golang-pam/pam.go
generated
vendored
|
|
@ -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
|
||||
}
|
||||
|
||||
90
vendor/github.com/vvanpo/golang-pam/pamdefs.c
generated
vendored
90
vendor/github.com/vvanpo/golang-pam/pamdefs.c
generated
vendored
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
63
vendor/github.com/vvanpo/golang-pam/pamdefs.go
generated
vendored
63
vendor/github.com/vvanpo/golang-pam/pamdefs.go
generated
vendored
|
|
@ -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
0
vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto
generated
vendored
Normal file → Executable file
0
vendor/google.golang.org/appengine/internal/regen.sh
generated
vendored
Normal file → Executable file
0
vendor/google.golang.org/appengine/internal/regen.sh
generated
vendored
Normal file → Executable file
0
vendor/google.golang.org/appengine/travis_install.sh
generated
vendored
Normal file → Executable file
0
vendor/google.golang.org/appengine/travis_install.sh
generated
vendored
Normal file → Executable file
0
vendor/google.golang.org/appengine/travis_test.sh
generated
vendored
Normal file → Executable file
0
vendor/google.golang.org/appengine/travis_test.sh
generated
vendored
Normal file → Executable file
Loading…
Add table
Add a link
Reference in a new issue