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.
All parsing code for C++98/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.
For C++, the easiest way is to clone the runtime library sources and build them along with your project.
Using Kaitai Struct in C++/STL usually consists of 3 steps.
std::istream). One can open local file for that, or use existing std::string or char* buffer.
        
        #include <fstream>
std::ifstream is("path/to/local/file.bin", std::ifstream::binary);
#include <sstream>
std::istringstream is(str);
#include <sstream>
const char buf[] = { ... };
std::string str(buf, sizeof buf);
std::istringstream is(str);
#include "kaitai/kaitaistream.h"
kaitai::kstream ks(&is);
sudoers_ts_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.records() // => get records
#ifndef SUDOERS_TS_H_
#define SUDOERS_TS_H_
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
class sudoers_ts_t;
#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <set>
#include <vector>
#if KAITAI_STRUCT_VERSION < 11000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.11 or later is required"
#endif
/**
 * 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.
 * \sa https://www.sudo.ws/docs/man/1.8.27/sudoers_timestamp.man/ Source
 */
class sudoers_ts_t : public kaitai::kstruct {
public:
    class record_t;
    class record_v1_t;
    class record_v2_t;
    class timespec_t;
    class ts_flag_t;
    enum ts_type_t {
        TS_TYPE_GLOBAL = 1,
        TS_TYPE_TTY = 2,
        TS_TYPE_PPID = 3,
        TS_TYPE_LOCKEXCL = 4
    };
    static bool _is_defined_ts_type_t(ts_type_t v);
private:
    static const std::set<ts_type_t> _values_ts_type_t;
    static std::set<ts_type_t> _build_values_ts_type_t();
public:
    sudoers_ts_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, sudoers_ts_t* p__root = 0);
private:
    void _read();
    void _clean_up();
public:
    ~sudoers_ts_t();
    class record_t : public kaitai::kstruct {
    public:
        record_t(kaitai::kstream* p__io, sudoers_ts_t* p__parent = 0, sudoers_ts_t* p__root = 0);
    private:
        void _read();
        void _clean_up();
    public:
        ~record_t();
    private:
        uint16_t m_version;
        uint16_t m_len_record;
        kaitai::kstruct* m_payload;
        bool n_payload;
    public:
        bool _is_null_payload() { payload(); return n_payload; };
    private:
        sudoers_ts_t* m__root;
        sudoers_ts_t* m__parent;
        std::string m__raw_payload;
        kaitai::kstream* m__io__raw_payload;
    public:
        /**
         * version number of the timestamp_entry struct
         */
        uint16_t version() const { return m_version; }
        /**
         * size of the record in bytes
         */
        uint16_t len_record() const { return m_len_record; }
        kaitai::kstruct* payload() const { return m_payload; }
        sudoers_ts_t* _root() const { return m__root; }
        sudoers_ts_t* _parent() const { return m__parent; }
        std::string _raw_payload() const { return m__raw_payload; }
        kaitai::kstream* _io__raw_payload() const { return m__io__raw_payload; }
    };
    class record_v1_t : public kaitai::kstruct {
    public:
        record_v1_t(kaitai::kstream* p__io, sudoers_ts_t::record_t* p__parent = 0, sudoers_ts_t* p__root = 0);
    private:
        void _read();
        void _clean_up();
    public:
        ~record_v1_t();
    private:
        ts_type_t m_type;
        ts_flag_t* m_flags;
        uint32_t m_auth_uid;
        uint32_t m_sid;
        timespec_t* m_ts;
        uint32_t m_ttydev;
        bool n_ttydev;
    public:
        bool _is_null_ttydev() { ttydev(); return n_ttydev; };
    private:
        uint32_t m_ppid;
        bool n_ppid;
    public:
        bool _is_null_ppid() { ppid(); return n_ppid; };
    private:
        sudoers_ts_t* m__root;
        sudoers_ts_t::record_t* m__parent;
    public:
        /**
         * record type
         */
        ts_type_t type() const { return m_type; }
        /**
         * record flags
         */
        ts_flag_t* flags() const { return m_flags; }
        /**
         * user ID that was used for authentication
         */
        uint32_t auth_uid() const { return m_auth_uid; }
        /**
         * session ID associated with tty/ppid
         */
        uint32_t sid() const { return m_sid; }
        /**
         * time stamp, from a monotonic time source
         */
        timespec_t* ts() const { return m_ts; }
        /**
         * device number of the terminal associated with the session
         */
        uint32_t ttydev() const { return m_ttydev; }
        /**
         * ID of the parent process
         */
        uint32_t ppid() const { return m_ppid; }
        sudoers_ts_t* _root() const { return m__root; }
        sudoers_ts_t::record_t* _parent() const { return m__parent; }
    };
    class record_v2_t : public kaitai::kstruct {
    public:
        record_v2_t(kaitai::kstream* p__io, sudoers_ts_t::record_t* p__parent = 0, sudoers_ts_t* p__root = 0);
    private:
        void _read();
        void _clean_up();
    public:
        ~record_v2_t();
    private:
        ts_type_t m_type;
        ts_flag_t* m_flags;
        uint32_t m_auth_uid;
        uint32_t m_sid;
        timespec_t* m_start_time;
        timespec_t* m_ts;
        uint32_t m_ttydev;
        bool n_ttydev;
    public:
        bool _is_null_ttydev() { ttydev(); return n_ttydev; };
    private:
        uint32_t m_ppid;
        bool n_ppid;
    public:
        bool _is_null_ppid() { ppid(); return n_ppid; };
    private:
        sudoers_ts_t* m__root;
        sudoers_ts_t::record_t* m__parent;
    public:
        /**
         * record type
         */
        ts_type_t type() const { return m_type; }
        /**
         * record flags
         */
        ts_flag_t* flags() const { return m_flags; }
        /**
         * user ID that was used for authentication
         */
        uint32_t auth_uid() const { return m_auth_uid; }
        /**
         * ID of the user's terminal session, if present (when type is TS_TTY)
         */
        uint32_t sid() const { return m_sid; }
        /**
         * start time of the session leader for records of type TS_TTY or of the parent process for records of type TS_PPID
         */
        timespec_t* start_time() const { return m_start_time; }
        /**
         * actual time stamp, from a monotonic time source
         */
        timespec_t* ts() const { return m_ts; }
        /**
         * device number of the terminal associated with the session
         */
        uint32_t ttydev() const { return m_ttydev; }
        /**
         * ID of the parent process
         */
        uint32_t ppid() const { return m_ppid; }
        sudoers_ts_t* _root() const { return m__root; }
        sudoers_ts_t::record_t* _parent() const { return m__parent; }
    };
    class timespec_t : public kaitai::kstruct {
    public:
        timespec_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, sudoers_ts_t* p__root = 0);
    private:
        void _read();
        void _clean_up();
    public:
        ~timespec_t();
    private:
        int64_t m_sec;
        int64_t m_nsec;
        sudoers_ts_t* m__root;
        kaitai::kstruct* m__parent;
    public:
        /**
         * seconds
         */
        int64_t sec() const { return m_sec; }
        /**
         * nanoseconds
         */
        int64_t nsec() const { return m_nsec; }
        sudoers_ts_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };
    class ts_flag_t : public kaitai::kstruct {
    public:
        ts_flag_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, sudoers_ts_t* p__root = 0);
    private:
        void _read();
        void _clean_up();
    public:
        ~ts_flag_t();
    private:
        uint64_t m_reserved0;
        bool m_anyuid;
        bool m_disabled;
        uint64_t m_reserved1;
        sudoers_ts_t* m__root;
        kaitai::kstruct* m__parent;
    public:
        /**
         * Reserved (unused) bits
         */
        uint64_t reserved0() const { return m_reserved0; }
        /**
         * ignore uid
         */
        bool anyuid() const { return m_anyuid; }
        /**
         * entry disabled
         */
        bool disabled() const { return m_disabled; }
        /**
         * Reserved (unused) bits
         */
        uint64_t reserved1() const { return m_reserved1; }
        sudoers_ts_t* _root() const { return m__root; }
        kaitai::kstruct* _parent() const { return m__parent; }
    };
private:
    std::vector<record_t*>* m_records;
    sudoers_ts_t* m__root;
    kaitai::kstruct* m__parent;
public:
    std::vector<record_t*>* records() const { return m_records; }
    sudoers_ts_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};
#endif  // SUDOERS_TS_H_
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "sudoers_ts.h"
std::set<sudoers_ts_t::ts_type_t> sudoers_ts_t::_build_values_ts_type_t() {
    std::set<sudoers_ts_t::ts_type_t> _t;
    _t.insert(sudoers_ts_t::TS_TYPE_GLOBAL);
    _t.insert(sudoers_ts_t::TS_TYPE_TTY);
    _t.insert(sudoers_ts_t::TS_TYPE_PPID);
    _t.insert(sudoers_ts_t::TS_TYPE_LOCKEXCL);
    return _t;
}
const std::set<sudoers_ts_t::ts_type_t> sudoers_ts_t::_values_ts_type_t = sudoers_ts_t::_build_values_ts_type_t();
bool sudoers_ts_t::_is_defined_ts_type_t(sudoers_ts_t::ts_type_t v) {
    return sudoers_ts_t::_values_ts_type_t.find(v) != sudoers_ts_t::_values_ts_type_t.end();
}
sudoers_ts_t::sudoers_ts_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, sudoers_ts_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root ? p__root : this;
    m_records = 0;
    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}
void sudoers_ts_t::_read() {
    m_records = new std::vector<record_t*>();
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_records->push_back(new record_t(m__io, this, m__root));
            i++;
        }
    }
}
sudoers_ts_t::~sudoers_ts_t() {
    _clean_up();
}
void sudoers_ts_t::_clean_up() {
    if (m_records) {
        for (std::vector<record_t*>::iterator it = m_records->begin(); it != m_records->end(); ++it) {
            delete *it;
        }
        delete m_records; m_records = 0;
    }
}
sudoers_ts_t::record_t::record_t(kaitai::kstream* p__io, sudoers_ts_t* p__parent, sudoers_ts_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m__io__raw_payload = 0;
    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}
void sudoers_ts_t::record_t::_read() {
    m_version = m__io->read_u2le();
    m_len_record = m__io->read_u2le();
    n_payload = true;
    switch (version()) {
    case 1: {
        n_payload = false;
        m__raw_payload = m__io->read_bytes(len_record() - 4);
        m__io__raw_payload = new kaitai::kstream(m__raw_payload);
        m_payload = new record_v1_t(m__io__raw_payload, this, m__root);
        break;
    }
    case 2: {
        n_payload = false;
        m__raw_payload = m__io->read_bytes(len_record() - 4);
        m__io__raw_payload = new kaitai::kstream(m__raw_payload);
        m_payload = new record_v2_t(m__io__raw_payload, this, m__root);
        break;
    }
    default: {
        m__raw_payload = m__io->read_bytes(len_record() - 4);
        break;
    }
    }
}
sudoers_ts_t::record_t::~record_t() {
    _clean_up();
}
void sudoers_ts_t::record_t::_clean_up() {
    if (!n_payload) {
        if (m__io__raw_payload) {
            delete m__io__raw_payload; m__io__raw_payload = 0;
        }
        if (m_payload) {
            delete m_payload; m_payload = 0;
        }
    }
}
sudoers_ts_t::record_v1_t::record_v1_t(kaitai::kstream* p__io, sudoers_ts_t::record_t* p__parent, sudoers_ts_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = 0;
    m_ts = 0;
    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}
void sudoers_ts_t::record_v1_t::_read() {
    m_type = static_cast<sudoers_ts_t::ts_type_t>(m__io->read_u2le());
    m_flags = new ts_flag_t(m__io, this, m__root);
    m_auth_uid = m__io->read_u4le();
    m_sid = m__io->read_u4le();
    m_ts = new timespec_t(m__io, this, m__root);
    n_ttydev = true;
    if (type() == sudoers_ts_t::TS_TYPE_TTY) {
        n_ttydev = false;
        m_ttydev = m__io->read_u4le();
    }
    n_ppid = true;
    if (type() == sudoers_ts_t::TS_TYPE_PPID) {
        n_ppid = false;
        m_ppid = m__io->read_u4le();
    }
}
sudoers_ts_t::record_v1_t::~record_v1_t() {
    _clean_up();
}
void sudoers_ts_t::record_v1_t::_clean_up() {
    if (m_flags) {
        delete m_flags; m_flags = 0;
    }
    if (m_ts) {
        delete m_ts; m_ts = 0;
    }
    if (!n_ttydev) {
    }
    if (!n_ppid) {
    }
}
sudoers_ts_t::record_v2_t::record_v2_t(kaitai::kstream* p__io, sudoers_ts_t::record_t* p__parent, sudoers_ts_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = 0;
    m_start_time = 0;
    m_ts = 0;
    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}
void sudoers_ts_t::record_v2_t::_read() {
    m_type = static_cast<sudoers_ts_t::ts_type_t>(m__io->read_u2le());
    m_flags = new ts_flag_t(m__io, this, m__root);
    m_auth_uid = m__io->read_u4le();
    m_sid = m__io->read_u4le();
    m_start_time = new timespec_t(m__io, this, m__root);
    m_ts = new timespec_t(m__io, this, m__root);
    n_ttydev = true;
    if (type() == sudoers_ts_t::TS_TYPE_TTY) {
        n_ttydev = false;
        m_ttydev = m__io->read_u4le();
    }
    n_ppid = true;
    if (type() == sudoers_ts_t::TS_TYPE_PPID) {
        n_ppid = false;
        m_ppid = m__io->read_u4le();
    }
}
sudoers_ts_t::record_v2_t::~record_v2_t() {
    _clean_up();
}
void sudoers_ts_t::record_v2_t::_clean_up() {
    if (m_flags) {
        delete m_flags; m_flags = 0;
    }
    if (m_start_time) {
        delete m_start_time; m_start_time = 0;
    }
    if (m_ts) {
        delete m_ts; m_ts = 0;
    }
    if (!n_ttydev) {
    }
    if (!n_ppid) {
    }
}
sudoers_ts_t::timespec_t::timespec_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, sudoers_ts_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}
void sudoers_ts_t::timespec_t::_read() {
    m_sec = m__io->read_s8le();
    m_nsec = m__io->read_s8le();
}
sudoers_ts_t::timespec_t::~timespec_t() {
    _clean_up();
}
void sudoers_ts_t::timespec_t::_clean_up() {
}
sudoers_ts_t::ts_flag_t::ts_flag_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, sudoers_ts_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    try {
        _read();
    } catch(...) {
        _clean_up();
        throw;
    }
}
void sudoers_ts_t::ts_flag_t::_read() {
    m_reserved0 = m__io->read_bits_int_be(6);
    m_anyuid = m__io->read_bits_int_be(1);
    m_disabled = m__io->read_bits_int_be(1);
    m_reserved1 = m__io->read_bits_int_be(8);
}
sudoers_ts_t::ts_flag_t::~ts_flag_t() {
    _clean_up();
}
void sudoers_ts_t::ts_flag_t::_clean_up() {
}