gosssd

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 3, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

README

GoSSSD

A Go library for direct interaction with SSSD (System Security Services Daemon) via its IPC protocol over Unix domain sockets. This allows Go programs to do user/group lookups in Linux environments using SSSD (typically, RHEL/Fedora variants) without needing to enable CGO and linking to glibc for NSS support.

Overview

GoSSSD provides a native Go client for communicating with SSSD's NSS (Name Service Switch) responder, allowing you to query user and group information without relying on CGO or libc NSS modules.

Features

  • Direct Unix socket communication with SSSD NSS responder
  • User lookups by name or UID
  • Group lookups by name or GID
  • Group membership queries
  • No CGO dependencies
  • Client object is not goroutine-safe; guard with your own locking or use one client per goroutine
  • Configurable timeouts, socket paths, and contexts
  • Integration tests with self-contained SSSD build on Linux
  • Mock server for cross-platform testing

Installation

go get github.com/bbockelm/gosssd

Usage

Basic Example
package main

import (
    "fmt"
    "log"

    "github.com/bbockelm/gosssd"
)

func main() {
    // Create a new client
    client := gosssd.NewClient()

    // Connect to SSSD
    if err := client.Connect(); err != nil {
        log.Fatalf("Failed to connect: %v", err)
    }
    defer client.Close()

    // Look up a user by name
    user, err := client.GetUserByName("testuser1")
    if err != nil {
        log.Fatalf("Failed to get user: %v", err)
    }

    fmt.Printf("User: %s (UID: %d, GID: %d)\n", user.Name, user.UID, user.GID)
    fmt.Printf("Home: %s, Shell: %s\n", user.HomeDir, user.Shell)
}
Custom Configuration
// Use custom socket path and timeout
client := gosssd.NewClient(
    gosssd.WithSocketPath("/var/lib/sss/pipes/nss"),
    gosssd.WithTimeout(10 * time.Second),
)
Available Operations
User Lookups
// By username
user, err := client.GetUserByName("username")

// By UID
user, err := client.GetUserByUID(1000)
Group Lookups
// By group name
group, err := client.GetGroupByName("groupname")

// By GID
group, err := client.GetGroupByGID(1000)
Group Membership
// Get all groups for a user
gids, err := client.GetGroupsForUser("username")
for _, gid := range gids {
    fmt.Printf("Member of GID: %d\n", gid)
}

Development

Prerequisites
  • Go 1.24 or later
  • Docker (for devcontainer)
  • VS Code with Remote-Containers extension (recommended)
Development Environment

This project includes a devcontainer configuration with AlmaLinux 9 and SSSD pre-configured:

  1. Open the project in VS Code
  2. Click "Reopen in Container" when prompted
  3. The container will build and configure SSSD automatically

The devcontainer includes:

  • Go 1.21+
  • All necessary build tools
Test Users

The devcontainer creates test users automatically:

  • testuser1 (UID: 10001)
  • testuser2 (UID: 10002)
  • testgroup (GID: 10100) - contains both test users

However, tests should fallback cleanly to more common Linux users like nobody if you're not in a container environment.

Protocol Details

SSSD NSS Protocol

The SSSD NSS responder uses a binary protocol over Unix domain sockets:

  1. Message Structure: Length-prefixed messages with a 16-byte header
  2. Encoding: Little-endian binary encoding
  3. Strings: Length-prefixed with null terminators
  4. Socket: Default path is /var/lib/sss/pipes/nss
Message Format
Header (16 bytes):
- Length (4 bytes): Total message length including header
- Command (4 bytes): Request/response type
- Status (4 bytes): Response status code
- Reserved (4 bytes): Reserved for future use

Data (variable):
- Request/response payload
Supported Commands
  • SSS_NSS_GETPWNAM: Get user by name
  • SSS_NSS_GETPWUID: Get user by UID
  • SSS_NSS_GETGRNAM: Get group by name
  • SSS_NSS_GETGRGID: Get group by GID
  • SSS_NSS_INITGR: Get groups for user

Architecture

┌─────────────┐
│  Your App   │
└──────┬──────┘
       │ gosssd.Client
       ▼
┌─────────────────────┐
│   Unix Socket       │
│ /var/lib/sss/pipes/ │
│      nss            │
└──────┬──────────────┘
       │
       ▼
┌─────────────────────┐
│  SSSD NSS Responder │
└──────┬──────────────┘
       │
       ▼
┌─────────────────────┐
│  Identity Provider  │
│  (LDAP/AD/IPA/etc)  │
└─────────────────────┘

Limitations

  • Currently implements only NSS protocol (no PAM, SSH, sudo responders). Only does the user/group lookups, not hosts.
  • No caching (relies on SSSD's caching)
  • Requires SSSD to be running and properly configured

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

References

Acknowledgments

This library implements the SSSD NSS responder protocol based on the SSSD project's specifications.

Documentation

Index

Constants

View Source
const (
	// Default socket paths
	DefaultNSSSocketPath = "/var/lib/sss/pipes/nss"

	// Protocol version
	ProtocolVersion = 1

	// Request commands (based on SSSD NSS responder protocol)
	// From src/sss_client/sss_cli.h
	SSS_GET_VERSION       = 0x0001 // Get protocol version
	SSS_NSS_GETPWNAM      = 0x0011 // Get user by name
	SSS_NSS_GETPWUID      = 0x0012 // Get user by UID
	SSS_NSS_SETPWENT      = 0x0013 // Begin user enumeration
	SSS_NSS_GETPWENT      = 0x0014 // Get next user entry
	SSS_NSS_ENDPWENT      = 0x0015 // End user enumeration
	SSS_NSS_GETGRNAM      = 0x0021 // Get group by name
	SSS_NSS_GETGRGID      = 0x0022 // Get group by GID
	SSS_NSS_SETGRENT      = 0x0023 // Begin group enumeration
	SSS_NSS_GETGRENT      = 0x0024 // Get next group entry
	SSS_NSS_ENDGRENT      = 0x0025 // End group enumeration
	SSS_NSS_INITGR        = 0x0026 // Get groups for user
	SSS_NSS_SETNETGRENT   = 0x0061 // Begin netgroup enumeration
	SSS_NSS_GETNETGRENT   = 0x0062 // Get next netgroup entry
	SSS_NSS_ENDNETGRENT   = 0x0063 // End netgroup enumeration
	SSS_NSS_GETSERVBYNAME = 0x00A1 // Get service by name
	SSS_NSS_GETSERVBYPORT = 0x00A2 // Get service by port
	SSS_NSS_SETSERVENT    = 0x00A3 // Begin service enumeration
	SSS_NSS_GETSERVENT    = 0x00A4 // Get next service entry
	SSS_NSS_ENDSERVENT    = 0x00A5 // End service enumeration

	// Response status codes
	SSS_NSS_STATUS_SUCCESS        = 0
	SSS_NSS_STATUS_NOTFOUND       = 1
	SSS_NSS_STATUS_UNAVAIL        = 2
	SSS_NSS_STATUS_TRYAGAIN       = 3
	SSS_NSS_STATUS_PROTOCOL_ERROR = 4
)

SSSD NSS protocol constants

Variables

This section is empty.

Functions

func MarshalRequest

func MarshalRequest(command uint32, data []byte) ([]byte, error)

MarshalRequest creates a binary request message

func MarshalString

func MarshalString(s string) []byte

MarshalString creates a null-terminated string for protocol messages For GETPWNAM requests, it's just the username as a null-terminated string

func UnmarshalString

func UnmarshalString(data []byte, offset int) (string, int, error)

UnmarshalString reads a length-prefixed string from data

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client represents a connection to the SSSD NSS responder. NOTE: Client is not goroutine-safe; callers must serialize access or use separate Client instances per goroutine.

func NewClient

func NewClient(opts ...ClientOption) *Client

NewClient creates a new SSSD NSS client

func (*Client) Close

func (c *Client) Close() error

Close closes the connection to SSSD

func (*Client) Connect

func (c *Client) Connect() error

Connect establishes a connection to the SSSD socket

func (*Client) ConnectContext

func (c *Client) ConnectContext(ctx context.Context) error

ConnectContext establishes a connection using the provided context for dialing and for managing the lifecycle of the connection (socket will be closed when ctx is done). This is a convenience wrapper that avoids storing the context on the client.

func (*Client) GetGroupByGID

func (c *Client) GetGroupByGID(gid uint32) (*Group, error)

GetGroupByGID looks up a group by GID

func (*Client) GetGroupByName

func (c *Client) GetGroupByName(groupname string) (*Group, error)

GetGroupByName looks up a group by name

func (*Client) GetGroupsForUser

func (c *Client) GetGroupsForUser(username string) ([]uint32, error)

GetGroupsForUser retrieves all groups that a user belongs to Protocol: INITGROUP Reply format 0-3: 32bit unsigned number of results 4-7: 32bit unsigned (reserved/padding) For each result: 0-3: 32bit number with gid

func (*Client) GetUserByName

func (c *Client) GetUserByName(username string) (*User, error)

GetUserByName looks up a user by username

func (*Client) GetUserByUID

func (c *Client) GetUserByUID(uid uint32) (*User, error)

GetUserByUID looks up a user by UID

type ClientOption

type ClientOption func(*Client)

ClientOption is a function that configures a Client

func WithContext

func WithContext(ctx context.Context) ClientOption

WithContext sets a context used to cancel in-flight operations.

func WithSocketPath

func WithSocketPath(path string) ClientOption

WithSocketPath sets a custom socket path

func WithTimeout

func WithTimeout(timeout time.Duration) ClientOption

WithTimeout sets the timeout for socket operations

type Group

type Group struct {
	Name    string
	Passwd  string
	GID     uint32
	Members []string
}

Group represents a group entry returned by SSSD

func UnmarshalGroup

func UnmarshalGroup(data []byte) (*Group, error)

UnmarshalGroup parses group data from a response Protocol format (from nss_group.c): 0-3: 32bit unsigned number of results 4-7: 32bit unsigned (reserved/padding) For each result:

0-3: 32bit number gid
4-7: 32bit unsigned number of members
8-X: sequence of 0 terminated strings (name, passwd, members...)

type MessageHeader

type MessageHeader struct {
	Length   uint32 // Total message length including header
	Command  uint32 // Command/request type
	Status   uint32 // Response status (for responses)
	Reserved uint32 // Reserved for future use
}

MessageHeader represents the SSSD protocol message header The protocol uses a simple TLV (Type-Length-Value) format

type Request

type Request struct {
	Header MessageHeader
	Data   []byte
}

Request represents a generic SSSD NSS request

type Response

type Response struct {
	Header MessageHeader
	Data   []byte
}

Response represents a generic SSSD NSS response

func UnmarshalResponse

func UnmarshalResponse(data []byte) (*Response, error)

UnmarshalResponse parses a binary response message

type User

type User struct {
	Name    string
	Passwd  string
	UID     uint32
	GID     uint32
	Gecos   string
	HomeDir string
	Shell   string
}

User represents a passwd entry returned by SSSD

func UnmarshalUser

func UnmarshalUser(data []byte) (*User, error)

UnmarshalUser parses user data from a response Protocol format (from nss_passwd.c): 0-3: 32bit unsigned number of results 4-7: 32bit unsigned (reserved/padding) For each result:

0-3: 32bit number uid
4-7: 32bit number gid
8-X: sequence of 5, 0 terminated, strings (name, passwd, gecos, dir, shell)

Directories

Path Synopsis
cmd
gosssd-cli command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL