diff options
Diffstat (limited to 'vendor/github.com/msteinert')
-rw-r--r-- | vendor/github.com/msteinert/pam/LICENSE | 24 | ||||
-rw-r--r-- | vendor/github.com/msteinert/pam/README.md | 36 | ||||
-rw-r--r-- | vendor/github.com/msteinert/pam/transaction.c | 51 | ||||
-rw-r--r-- | vendor/github.com/msteinert/pam/transaction.go | 319 |
4 files changed, 430 insertions, 0 deletions
diff --git a/vendor/github.com/msteinert/pam/LICENSE b/vendor/github.com/msteinert/pam/LICENSE new file mode 100644 index 00000000..e3adca07 --- /dev/null +++ b/vendor/github.com/msteinert/pam/LICENSE @@ -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. diff --git a/vendor/github.com/msteinert/pam/README.md b/vendor/github.com/msteinert/pam/README.md new file mode 100644 index 00000000..21851ed8 --- /dev/null +++ b/vendor/github.com/msteinert/pam/README.md @@ -0,0 +1,36 @@ +[](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. There's not much +else to be said. PAM is a simple API and now it's available for use in Go +applications. + +There's an example of a "fake login" program in the examples directory. +Look at the pam module's [godocs][1] for details about the Go API, or refer +to the official [PAM documentation][2]. + +## 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 diff --git a/vendor/github.com/msteinert/pam/transaction.c b/vendor/github.com/msteinert/pam/transaction.c new file mode 100644 index 00000000..4ff649b1 --- /dev/null +++ b/vendor/github.com/msteinert/pam/transaction.c @@ -0,0 +1,51 @@ +#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, + 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; +} + +struct pam_conv *make_pam_conv(void *appdata_ptr) +{ + struct pam_conv* conv = malloc(sizeof *conv); + if (!conv) { + return NULL; + } + conv->conv = cb_pam_conv; + conv->appdata_ptr = appdata_ptr; + return conv; +} diff --git a/vendor/github.com/msteinert/pam/transaction.go b/vendor/github.com/msteinert/pam/transaction.go new file mode 100644 index 00000000..360d89a6 --- /dev/null +++ b/vendor/github.com/msteinert/pam/transaction.go @@ -0,0 +1,319 @@ +package pam + +//#include <security/pam_appl.h> +//#include <stdlib.h> +//#cgo CFLAGS: -Wall -std=c99 +//#cgo LDFLAGS: -lpam +//struct pam_conv *make_pam_conv(void *); +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) +} + +// Internal conversation structure +type conversation struct { + handler ConversationHandler + conv *C.struct_pam_conv +} + +// Constructs 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, C.int) { + c := &conversation{} + c.handler = handler + c.conv = C.make_pam_conv(unsafe.Pointer(c)) + if c.conv == nil { + return nil, C.PAM_BUF_ERR + } + return c, C.PAM_SUCCESS +} + +// 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. +//export cbPAMConv +func cbPAMConv(s C.int, msg *C.char, appdata unsafe.Pointer) (*C.char, C.int) { + c := (*conversation)(appdata) + r, err := c.handler.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 *conversation + status C.int +} + +// Finalize a PAM transaction. +func transactionFinalizer(t *Transaction) { + C.pam_end(t.handle, t.status) + C.free(unsafe.Pointer(t.conv.conv)) +} + +// 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{} + t.conv, t.status = newConversation(handler) + if t.status != C.PAM_SUCCESS { + return nil, t + } + 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.conv, &t.handle) + if t.status != C.PAM_SUCCESS { + C.free(unsafe.Pointer(t.conv.conv)) + return nil, t + } + runtime.SetFinalizer(t, transactionFinalizer) + 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 +} |