This spec can be used to parse sudo time stamp files located in directories such as /run/sudo/ts/$USER or /var/lib/sudo/ts/$USER.
This page hosts a formal specification of Sudoers Time Stamp file using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.
import (
"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
"bytes"
)
/**
* This spec can be used to parse sudo time stamp files located in directories
* such as /run/sudo/ts/$USER or /var/lib/sudo/ts/$USER.
* @see <a href="https://www.sudo.ws/docs/man/1.8.27/sudoers_timestamp.man/">Source</a>
*/
type SudoersTs_TsType int
const (
SudoersTs_TsType__Global SudoersTs_TsType = 1
SudoersTs_TsType__Tty SudoersTs_TsType = 2
SudoersTs_TsType__Ppid SudoersTs_TsType = 3
SudoersTs_TsType__Lockexcl SudoersTs_TsType = 4
)
var values_SudoersTs_TsType = map[SudoersTs_TsType]struct{}{1: {}, 2: {}, 3: {}, 4: {}}
func (v SudoersTs_TsType) isDefined() bool {
_, ok := values_SudoersTs_TsType[v]
return ok
}
type SudoersTs struct {
Records []*SudoersTs_Record
_io *kaitai.Stream
_root *SudoersTs
_parent kaitai.Struct
}
func NewSudoersTs() *SudoersTs {
return &SudoersTs{
}
}
func (this SudoersTs) IO_() *kaitai.Stream {
return this._io
}
func (this *SudoersTs) Read(io *kaitai.Stream, parent kaitai.Struct, root *SudoersTs) (err error) {
this._io = io
this._parent = parent
this._root = root
for i := 0;; i++ {
tmp1, err := this._io.EOF()
if err != nil {
return err
}
if tmp1 {
break
}
tmp2 := NewSudoersTs_Record()
err = tmp2.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Records = append(this.Records, tmp2)
}
return err
}
type SudoersTs_Record struct {
Version uint16
LenRecord uint16
Payload interface{}
_io *kaitai.Stream
_root *SudoersTs
_parent *SudoersTs
_raw_Payload []byte
}
func NewSudoersTs_Record() *SudoersTs_Record {
return &SudoersTs_Record{
}
}
func (this SudoersTs_Record) IO_() *kaitai.Stream {
return this._io
}
func (this *SudoersTs_Record) Read(io *kaitai.Stream, parent *SudoersTs, root *SudoersTs) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp3, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Version = uint16(tmp3)
tmp4, err := this._io.ReadU2le()
if err != nil {
return err
}
this.LenRecord = uint16(tmp4)
switch (this.Version) {
case 1:
tmp5, err := this._io.ReadBytes(int(this.LenRecord - 4))
if err != nil {
return err
}
tmp5 = tmp5
this._raw_Payload = tmp5
_io__raw_Payload := kaitai.NewStream(bytes.NewReader(this._raw_Payload))
tmp6 := NewSudoersTs_RecordV1()
err = tmp6.Read(_io__raw_Payload, this, this._root)
if err != nil {
return err
}
this.Payload = tmp6
case 2:
tmp7, err := this._io.ReadBytes(int(this.LenRecord - 4))
if err != nil {
return err
}
tmp7 = tmp7
this._raw_Payload = tmp7
_io__raw_Payload := kaitai.NewStream(bytes.NewReader(this._raw_Payload))
tmp8 := NewSudoersTs_RecordV2()
err = tmp8.Read(_io__raw_Payload, this, this._root)
if err != nil {
return err
}
this.Payload = tmp8
default:
tmp9, err := this._io.ReadBytes(int(this.LenRecord - 4))
if err != nil {
return err
}
tmp9 = tmp9
this._raw_Payload = tmp9
}
return err
}
/**
* version number of the timestamp_entry struct
*/
/**
* size of the record in bytes
*/
type SudoersTs_RecordV1 struct {
Type SudoersTs_TsType
Flags *SudoersTs_TsFlag
AuthUid uint32
Sid uint32
Ts *SudoersTs_Timespec
Ttydev uint32
Ppid uint32
_io *kaitai.Stream
_root *SudoersTs
_parent *SudoersTs_Record
}
func NewSudoersTs_RecordV1() *SudoersTs_RecordV1 {
return &SudoersTs_RecordV1{
}
}
func (this SudoersTs_RecordV1) IO_() *kaitai.Stream {
return this._io
}
func (this *SudoersTs_RecordV1) Read(io *kaitai.Stream, parent *SudoersTs_Record, root *SudoersTs) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp10, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Type = SudoersTs_TsType(tmp10)
tmp11 := NewSudoersTs_TsFlag()
err = tmp11.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Flags = tmp11
tmp12, err := this._io.ReadU4le()
if err != nil {
return err
}
this.AuthUid = uint32(tmp12)
tmp13, err := this._io.ReadU4le()
if err != nil {
return err
}
this.Sid = uint32(tmp13)
tmp14 := NewSudoersTs_Timespec()
err = tmp14.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Ts = tmp14
if (this.Type == SudoersTs_TsType__Tty) {
tmp15, err := this._io.ReadU4le()
if err != nil {
return err
}
this.Ttydev = uint32(tmp15)
}
if (this.Type == SudoersTs_TsType__Ppid) {
tmp16, err := this._io.ReadU4le()
if err != nil {
return err
}
this.Ppid = uint32(tmp16)
}
return err
}
/**
* record type
*/
/**
* record flags
*/
/**
* user ID that was used for authentication
*/
/**
* session ID associated with tty/ppid
*/
/**
* time stamp, from a monotonic time source
*/
/**
* device number of the terminal associated with the session
*/
/**
* ID of the parent process
*/
type SudoersTs_RecordV2 struct {
Type SudoersTs_TsType
Flags *SudoersTs_TsFlag
AuthUid uint32
Sid uint32
StartTime *SudoersTs_Timespec
Ts *SudoersTs_Timespec
Ttydev uint32
Ppid uint32
_io *kaitai.Stream
_root *SudoersTs
_parent *SudoersTs_Record
}
func NewSudoersTs_RecordV2() *SudoersTs_RecordV2 {
return &SudoersTs_RecordV2{
}
}
func (this SudoersTs_RecordV2) IO_() *kaitai.Stream {
return this._io
}
func (this *SudoersTs_RecordV2) Read(io *kaitai.Stream, parent *SudoersTs_Record, root *SudoersTs) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp17, err := this._io.ReadU2le()
if err != nil {
return err
}
this.Type = SudoersTs_TsType(tmp17)
tmp18 := NewSudoersTs_TsFlag()
err = tmp18.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Flags = tmp18
tmp19, err := this._io.ReadU4le()
if err != nil {
return err
}
this.AuthUid = uint32(tmp19)
tmp20, err := this._io.ReadU4le()
if err != nil {
return err
}
this.Sid = uint32(tmp20)
tmp21 := NewSudoersTs_Timespec()
err = tmp21.Read(this._io, this, this._root)
if err != nil {
return err
}
this.StartTime = tmp21
tmp22 := NewSudoersTs_Timespec()
err = tmp22.Read(this._io, this, this._root)
if err != nil {
return err
}
this.Ts = tmp22
if (this.Type == SudoersTs_TsType__Tty) {
tmp23, err := this._io.ReadU4le()
if err != nil {
return err
}
this.Ttydev = uint32(tmp23)
}
if (this.Type == SudoersTs_TsType__Ppid) {
tmp24, err := this._io.ReadU4le()
if err != nil {
return err
}
this.Ppid = uint32(tmp24)
}
return err
}
/**
* record type
*/
/**
* record flags
*/
/**
* user ID that was used for authentication
*/
/**
* ID of the user's terminal session, if present (when type is TS_TTY)
*/
/**
* start time of the session leader for records of type TS_TTY or of the parent process for records of type TS_PPID
*/
/**
* actual time stamp, from a monotonic time source
*/
/**
* device number of the terminal associated with the session
*/
/**
* ID of the parent process
*/
type SudoersTs_Timespec struct {
Sec int64
Nsec int64
_io *kaitai.Stream
_root *SudoersTs
_parent kaitai.Struct
}
func NewSudoersTs_Timespec() *SudoersTs_Timespec {
return &SudoersTs_Timespec{
}
}
func (this SudoersTs_Timespec) IO_() *kaitai.Stream {
return this._io
}
func (this *SudoersTs_Timespec) Read(io *kaitai.Stream, parent kaitai.Struct, root *SudoersTs) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp25, err := this._io.ReadS8le()
if err != nil {
return err
}
this.Sec = int64(tmp25)
tmp26, err := this._io.ReadS8le()
if err != nil {
return err
}
this.Nsec = int64(tmp26)
return err
}
/**
* seconds
*/
/**
* nanoseconds
*/
type SudoersTs_TsFlag struct {
Reserved0 uint64
Anyuid bool
Disabled bool
Reserved1 uint64
_io *kaitai.Stream
_root *SudoersTs
_parent kaitai.Struct
}
func NewSudoersTs_TsFlag() *SudoersTs_TsFlag {
return &SudoersTs_TsFlag{
}
}
func (this SudoersTs_TsFlag) IO_() *kaitai.Stream {
return this._io
}
func (this *SudoersTs_TsFlag) Read(io *kaitai.Stream, parent kaitai.Struct, root *SudoersTs) (err error) {
this._io = io
this._parent = parent
this._root = root
tmp27, err := this._io.ReadBitsIntBe(6)
if err != nil {
return err
}
this.Reserved0 = tmp27
tmp28, err := this._io.ReadBitsIntBe(1)
if err != nil {
return err
}
this.Anyuid = tmp28 != 0
tmp29, err := this._io.ReadBitsIntBe(1)
if err != nil {
return err
}
this.Disabled = tmp29 != 0
tmp30, err := this._io.ReadBitsIntBe(8)
if err != nil {
return err
}
this.Reserved1 = tmp30
return err
}
/**
* Reserved (unused) bits
*/
/**
* ignore uid
*/
/**
* entry disabled
*/
/**
* Reserved (unused) bits
*/