diff options
Diffstat (limited to 'pam')
| -rw-r--r-- | pam/constants.go | 2 | ||||
| -rw-r--r-- | pam/login.go | 8 | ||||
| -rw-r--r-- | pam/pam.c | 12 | ||||
| -rw-r--r-- | pam/pam.go | 82 | ||||
| -rw-r--r-- | pam/pam.h | 7 | ||||
| -rw-r--r-- | pam/pam_test.go | 24 |
6 files changed, 97 insertions, 38 deletions
diff --git a/pam/constants.go b/pam/constants.go index 5c57e06..d2d0cf3 100644 --- a/pam/constants.go +++ b/pam/constants.go @@ -52,7 +52,7 @@ package pam */ import "C" -// Item is a an PAM information type. +// Item is a PAM information type. type Item int // PAM Item types. diff --git a/pam/login.go b/pam/login.go index 346edd4..e4f8f83 100644 --- a/pam/login.go +++ b/pam/login.go @@ -48,9 +48,10 @@ var ( tokenToCheck *crypto.Key ) -// userInput is run when the the callback needs some input from the user. We -// prompt the user for information and return their answer. A return value of -// nil indicates an error occurred. +// userInput is run when the callback needs some input from the user. We prompt +// the user for information and return their answer. A return value of nil +// indicates an error occurred. +// //export userInput func userInput(prompt *C.char) *C.char { fmt.Print(C.GoString(prompt)) @@ -65,6 +66,7 @@ func userInput(prompt *C.char) *C.char { // passphraseInput is run when the callback needs a passphrase from the user. We // pass along the tokenToCheck without prompting. A return value of nil // indicates an error occurred. +// //export passphraseInput func passphraseInput(prompt *C.char) *C.char { log.Printf("getting secret data for PAM: %q", C.GoString(prompt)) @@ -19,11 +19,11 @@ #include "pam.h" +#include <security/pam_appl.h> +#include <security/pam_ext.h> #include <stdio.h> #include <stdlib.h> #include <string.h> - -#include <security/pam_appl.h> #include <sys/mman.h> // mlock/munlock #include "_cgo_export.h" // for input callbacks @@ -94,7 +94,7 @@ void freeArray(pam_handle_t* pamh, void** array, int error_status) { void* copyIntoSecret(void* data) { size_t size = strlen(data) + 1; // include null terminator - void* copy = malloc(size); + void* copy = calloc(1, size); // initialize to avoid a compiler warning mlock(copy, size); memcpy(copy, data, size); return copy; @@ -102,9 +102,13 @@ void* copyIntoSecret(void* data) { void freeSecret(pam_handle_t* pamh, char* data, int error_status) { size_t size = strlen(data) + 1; // Include null terminator - // Use volitile function pointer to actually clear the memory. + // Use volatile function pointer to actually clear the memory. static void* (*const volatile memset_sec)(void*, int, size_t) = &memset; memset_sec(data, 0, size); munlock(data, size); free(data); } + +void infoMessage(pam_handle_t* pamh, const char* message) { + pam_info(pamh, "%s", message); +} @@ -35,16 +35,14 @@ import ( "unsafe" "github.com/google/fscrypt/security" - "github.com/google/fscrypt/util" ) // Handle wraps the C pam_handle_t type. This is used from within modules. type Handle struct { - handle *C.pam_handle_t - status C.int - // OrigUser is the user who invoked the PAM module (usually root) - OrigUser *user.User - // PamUser is the user who the PAM module is for + handle *C.pam_handle_t + status C.int + origPrivs *security.Privileges + // PamUser is the user for whom the PAM module is running. PamUser *user.User } @@ -58,17 +56,12 @@ func NewHandle(pamh unsafe.Pointer) (*Handle, error) { var pamUsername *C.char h.status = C.pam_get_user(h.handle, &pamUsername, nil) - if err := h.err(); err != nil { + if err = h.err(); err != nil { return nil, err } - if h.PamUser, err = user.Lookup(C.GoString(pamUsername)); err != nil { - return nil, err - } - if h.OrigUser, err = util.EffectiveUser(); err != nil { - return nil, err - } - return h, nil + h.PamUser, err = user.Lookup(C.GoString(pamUsername)) + return h, err } func (h *Handle) setData(name string, data unsafe.Pointer, cleanup C.CleanupFunc) error { @@ -86,7 +79,7 @@ func (h *Handle) getData(name string) (unsafe.Pointer, error) { return data, h.err() } -// ClearData remotes the PAM data with the specified name. +// ClearData removes the PAM data with the specified name. func (h *Handle) ClearData(name string) error { return h.setData(name, unsafe.Pointer(C.CString("")), C.CleanupFunc(C.freeData)) } @@ -99,8 +92,8 @@ func (h *Handle) SetSecret(name string, secret unsafe.Pointer) error { } // GetSecret returns a pointer to the C string PAM data with the specified name. -// This a pointer directory to the data, so it shouldn't be modified. It should -// have been previously set with SetSecret(). +// This is a pointer directly to the data, so it shouldn't be modified. It +// should have been previously set with SetSecret(). func (h *Handle) GetSecret(name string) (unsafe.Pointer, error) { return h.getData(name) } @@ -120,28 +113,54 @@ func (h *Handle) GetString(name string) (string, error) { return C.GoString((*C.char)(data)), nil } -// GetItem retrieves a PAM information item. This a pointer directory to the +// GetItem retrieves a PAM information item. This is a pointer directly to the // data, so it shouldn't be modified. func (h *Handle) GetItem(i Item) (unsafe.Pointer, error) { var data unsafe.Pointer h.status = C.pam_get_item(h.handle, C.int(i), &data) - return data, h.err() + if err := h.err(); err != nil { + return nil, err + } + if data == nil { + return nil, errors.New("item not found") + } + return data, nil +} + +// GetServiceName retrieves the name of the application running the PAM transaction. +func (h *Handle) GetServiceName() string { + data, err := h.GetItem(Service) + if err != nil { + return "[unknown service]" + } + return C.GoString((*C.char)(data)) } -// StartAsPamUser sets the effective privileges to that of the PAM user, and -// configures the PAM user's keyrings to be properly linked. +// StartAsPamUser sets the effective privileges to that of the PAM user. func (h *Handle) StartAsPamUser() error { - if _, err := security.UserKeyringID(h.PamUser, true); err != nil { - log.Printf("Setting up keyrings in PAM: %v", err) + userPrivs, err := security.UserPrivileges(h.PamUser) + if err != nil { + return err + } + origPrivs, err := security.ProcessPrivileges() + if err != nil { + return err } - return security.SetThreadPrivileges(h.PamUser) + if err = security.SetProcessPrivileges(userPrivs); err != nil { + return err + } + h.origPrivs = origPrivs + return nil } // StopAsPamUser restores the original privileges that were running the -// PAM module (this is usually root). As this error is often ignored in a defer -// statement, any error is also logged. +// PAM module (this is usually root). func (h *Handle) StopAsPamUser() error { - err := security.SetThreadPrivileges(h.OrigUser) + if h.origPrivs == nil { + return nil + } + err := security.SetProcessPrivileges(h.origPrivs) + h.origPrivs = nil if err != nil { log.Print(err) } @@ -156,8 +175,15 @@ func (h *Handle) err() error { return errors.New(s) } +// InfoMessage sends a message to the application using pam_info(). +func (h *Handle) InfoMessage(message string) { + cMessage := C.CString(message) + defer C.free(unsafe.Pointer(cMessage)) + C.infoMessage(h.handle, cMessage) +} + // Transaction represents a wrapped pam_handle_t type created with pam_start -// form an application. +// from an application. type Transaction Handle // Start initializes a pam Transaction. End() should be called after the @@ -23,7 +23,7 @@ #include <security/pam_appl.h> // Conversation that will call back into Go code when appropriate. -const struct pam_conv *goConv; +extern const struct pam_conv *goConv; // CleaupFuncs are used to cleanup specific PAM data. typedef void (*CleanupFunc)(pam_handle_t *pamh, void *data, int error_status); @@ -35,10 +35,13 @@ void freeData(pam_handle_t *pamh, void *data, int error_status); // then frees the array itself. void freeArray(pam_handle_t *pamh, void **array, int error_status); -// Creates a copy of a C string, which resides in an locked buffer. +// Creates a copy of a C string, which resides in a locked buffer. void *copyIntoSecret(void *data); // CleaupFunc that Zeros wipes a C string and unlocks and frees its memory. void freeSecret(pam_handle_t *pamh, char *data, int error_status); +// Sends a message to the application using pam_info(). +void infoMessage(pam_handle_t *pamh, const char *message); + #endif // FSCRYPT_PAM_H diff --git a/pam/pam_test.go b/pam/pam_test.go new file mode 100644 index 0000000..97cc792 --- /dev/null +++ b/pam/pam_test.go @@ -0,0 +1,24 @@ +/* + * pam_test.go - Stub test file that has one test that always passes. + * + * Copyright 2018 Google Inc. + * Author: Joe Richey (joerichey@google.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package pam + +import "testing" + +func TestTrivial(t *testing.T) {} |