aboutsummaryrefslogtreecommitdiff
path: root/pam
diff options
context:
space:
mode:
Diffstat (limited to 'pam')
-rw-r--r--pam/constants.go2
-rw-r--r--pam/login.go8
-rw-r--r--pam/pam.c12
-rw-r--r--pam/pam.go82
-rw-r--r--pam/pam.h7
-rw-r--r--pam/pam_test.go24
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))
diff --git a/pam/pam.c b/pam/pam.c
index 4769705..1d6aefe 100644
--- a/pam/pam.c
+++ b/pam/pam.c
@@ -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);
+}
diff --git a/pam/pam.go b/pam/pam.go
index 0f20f30..ea1c34e 100644
--- a/pam/pam.go
+++ b/pam/pam.go
@@ -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
diff --git a/pam/pam.h b/pam/pam.h
index 09afb2e..3cb609a 100644
--- a/pam/pam.h
+++ b/pam/pam.h
@@ -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) {}