|  | @@ -1,10 +1,11 @@
 | 
	
		
			
				|  |  | +// 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
 | 
	
		
			
				|  |  | -//struct pam_conv *make_pam_conv(void *);
 | 
	
		
			
				|  |  | +//void init_pam_conv(struct pam_conv *conv, long c);
 | 
	
		
			
				|  |  |  import "C"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import (
 | 
	
	
		
			
				|  | @@ -50,31 +51,16 @@ 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.
 | 
	
		
			
				|  |  | +// cbPAMConv is a wrapper for the conversation callback function.
 | 
	
		
			
				|  |  |  //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))
 | 
	
		
			
				|  |  | +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
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -84,14 +70,16 @@ func cbPAMConv(s C.int, msg *C.char, appdata unsafe.Pointer) (*C.char, C.int) {
 | 
	
		
			
				|  |  |  // Transaction is the application's handle for a PAM transaction.
 | 
	
		
			
				|  |  |  type Transaction struct {
 | 
	
		
			
				|  |  |  	handle *C.pam_handle_t
 | 
	
		
			
				|  |  | -	conv   *conversation
 | 
	
		
			
				|  |  | +	conv   *C.struct_pam_conv
 | 
	
		
			
				|  |  |  	status C.int
 | 
	
		
			
				|  |  | +	c      int
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// Finalize a PAM transaction.
 | 
	
		
			
				|  |  | +// transactionFinalizer cleans up the PAM handle and deletes the callback
 | 
	
		
			
				|  |  | +// function.
 | 
	
		
			
				|  |  |  func transactionFinalizer(t *Transaction) {
 | 
	
		
			
				|  |  |  	C.pam_end(t.handle, t.status)
 | 
	
		
			
				|  |  | -	C.free(unsafe.Pointer(t.conv.conv))
 | 
	
		
			
				|  |  | +	cbDelete(t.c)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Start initiates a new PAM transaction. Service is treated identically to
 | 
	
	
		
			
				|  | @@ -100,11 +88,12 @@ func transactionFinalizer(t *Transaction) {
 | 
	
		
			
				|  |  |  // 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
 | 
	
		
			
				|  |  | +	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
 | 
	
	
		
			
				|  | @@ -112,12 +101,10 @@ func Start(service, user string, handler ConversationHandler) (*Transaction, err
 | 
	
		
			
				|  |  |  		u = C.CString(user)
 | 
	
		
			
				|  |  |  		defer C.free(unsafe.Pointer(u))
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	t.status = C.pam_start(s, u, t.conv.conv, &t.handle)
 | 
	
		
			
				|  |  | +	t.status = C.pam_start(s, u, t.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
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |