Initial commit
This commit is contained in:
20
Makefile
Normal file
20
Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
.PHONY: all pam install examples clean
|
||||
|
||||
all: install examples
|
||||
|
||||
pam:
|
||||
gomake -C pam
|
||||
|
||||
install: pam
|
||||
gomake -C pam install
|
||||
|
||||
examples:
|
||||
gomake -C examples
|
||||
|
||||
clean:
|
||||
gomake -C pam clean
|
||||
gomake -C examples clean
|
||||
|
||||
|
||||
14
README
Normal file
14
README
Normal file
@@ -0,0 +1,14 @@
|
||||
It's Go! It's PAM (Pluggable Authentication Modules)! It's GoPAM!
|
||||
|
||||
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 for details about the Go
|
||||
API; for a more general PAM application API reference, peep
|
||||
|
||||
http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/adg-interface-by-app-expected.html
|
||||
|
||||
In the future, maybe the module API will be wrapped too. I don't know!
|
||||
|
||||
11
examples/Makefile
Normal file
11
examples/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
# Copyright 2009 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
TARG=fakelogin
|
||||
GOFILES=\
|
||||
fakelogin.go
|
||||
|
||||
include $(GOROOT)/src/Make.cmd
|
||||
74
examples/fakelogin.go
Normal file
74
examples/fakelogin.go
Normal file
@@ -0,0 +1,74 @@
|
||||
// This is a fake login implementation! It 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.
|
||||
//
|
||||
// It's not a real login for several reasons:
|
||||
//
|
||||
// (!WARNING!) It echos your password to the terminal (!WARNING!)
|
||||
// It doesn't switch users.
|
||||
// It's not a real login.
|
||||
//
|
||||
// It does however demonstrate a simple but powerful use of Go PAM.
|
||||
|
||||
package main
|
||||
|
||||
import(
|
||||
"fmt"
|
||||
"pam"
|
||||
"os"
|
||||
"bufio"
|
||||
)
|
||||
|
||||
func GetLine(prompt string) (string,bool) {
|
||||
fmt.Print(prompt)
|
||||
in := bufio.NewReader(os.Stdin)
|
||||
input,err := in.ReadString('\n')
|
||||
if err != nil {
|
||||
return "",false
|
||||
}
|
||||
return input[:len(input)-1],true
|
||||
}
|
||||
|
||||
// Echo on/off is ignored; echo will always happen.
|
||||
func DumbPrompter(style int, msg string) (string,bool) {
|
||||
switch style {
|
||||
case pam.PROMPT_ECHO_OFF:
|
||||
return GetLine(msg)
|
||||
case pam.PROMPT_ECHO_ON:
|
||||
return GetLine(msg)
|
||||
case pam.ERROR_MSG:
|
||||
fmt.Fprintf(os.Stderr, "Error: %s\n", msg)
|
||||
return "",true
|
||||
case pam.TEXT_INFO:
|
||||
fmt.Println(msg)
|
||||
return "",true
|
||||
}
|
||||
return "",false
|
||||
}
|
||||
|
||||
func main() {
|
||||
t,status := pam.Start("", "", pam.ResponseFunc(DumbPrompter))
|
||||
if status != pam.SUCCESS {
|
||||
fmt.Fprintf(os.Stderr, "Start() failed: %s\n", t.Error(status))
|
||||
return
|
||||
}
|
||||
defer func(){ t.End(status) }()
|
||||
|
||||
status = t.Authenticate(0)
|
||||
if status != pam.SUCCESS {
|
||||
fmt.Fprintf(os.Stderr, "Auth failed: %s\n", t.Error(status))
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Authentication succeeded!\n")
|
||||
fmt.Printf("Goodbye, friend.\n")
|
||||
}
|
||||
|
||||
16
pam/Makefile
Normal file
16
pam/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
include $(GOROOT)/src/Make.inc
|
||||
TARG=pam
|
||||
GOFILES:=pamdefs.go
|
||||
CGOFILES:=pam.go
|
||||
CGO_LDFLAGS:=-lpam
|
||||
CGO_OFILES:=gopam.o
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
|
||||
DOLLAR:="$"
|
||||
|
||||
pamdefs.go: pamdefs.c
|
||||
godefs `echo -n $(CGO_FLAGS) | sed 's/\(^ ^$(DOLLAR)]*\)/-f \1/g'` -g pam pamdefs.c > pamdefs.go
|
||||
gofmt -w pamdefs.go
|
||||
|
||||
|
||||
68
pam/gopam.c
Normal file
68
pam/gopam.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <security/_pam_types.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "gopam.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
pam/gopam.h
Normal file
11
pam/gopam.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#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);
|
||||
|
||||
185
pam/pam.go
Normal file
185
pam/pam.go
Normal file
@@ -0,0 +1,185 @@
|
||||
// Package pam provides a wrapper for the application layer of the
|
||||
// Pluggable Authentication Modules library.
|
||||
package pam
|
||||
|
||||
import (
|
||||
//#include "gopam.h"
|
||||
"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
|
||||
}
|
||||
|
||||
// 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{}
|
||||
conv := newConversation(handler)
|
||||
var status C.int
|
||||
if len(user) == 0 {
|
||||
status = C.pam_start(C.CString(serviceName), nil, conv.cconv, &t.handle)
|
||||
} else {
|
||||
status = C.pam_start(C.CString(serviceName), C.CString(user), conv.cconv, &t.handle)
|
||||
}
|
||||
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.
|
||||
func (t *Transaction) End(status int) {
|
||||
C.pam_end(t.handle, C.int(status))
|
||||
}
|
||||
|
||||
// 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.Split(nameval, "=", 2)
|
||||
env[chunks[0]] = chunks[1]
|
||||
list += (uintptr)(unsafe.Sizeof(list))
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
74
pam/pamdefs.c
Normal file
74
pam/pamdefs.c
Normal file
@@ -0,0 +1,74 @@
|
||||
#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,
|
||||
$BAD_ITEM = PAM_BAD_ITEM,
|
||||
$CONV_AGAIN = PAM_CONV_AGAIN,
|
||||
$INCOMPLETE = PAM_INCOMPLETE
|
||||
};
|
||||
|
||||
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
pam/pamdefs.go
Normal file
63
pam/pamdefs.go
Normal file
@@ -0,0 +1,63 @@
|
||||
// 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
|
||||
Reference in New Issue
Block a user