mdm

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Sep 10, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package mdm defines enrollment identities and decodes Apple MDM check-in, command and response envelopes.

Design

Generated registries supply message and payload types; this package adds MessageType dispatch, typed command construction and the surrounding protocol fields. Enrollment.Resolve distinguishes device, user, Shared iPad and User Enrollment channels. Original message bytes are retained for signature and forwarding paths.

The package does not authorize requests or persist enrollment state. server/service applies lifecycle and admission policy, storage defines persistence contracts, and server/httpapi provides transport handling.

References

Index

Constants

View Source
const SharedIPadUserID = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"

SharedIPadUserID is the sentinel UserID Apple sends on the shared iPad user channel; the real user is in UserShortName.

Variables

View Source
var (
	ErrNoEnrollmentID     = errors.New("mdm: message carries neither UDID nor EnrollmentID")
	ErrInvalidEnrollment  = errors.New("mdm: invalid enrollment identity")
	ErrSharedIPadNoUser   = errors.New("mdm: shared iPad user channel without UserShortName")
	ErrUnknownMessageType = errors.New("mdm: unknown check-in MessageType")
	ErrInvalidCommand     = errors.New("mdm: invalid command")
	ErrInvalidResponse    = errors.New("mdm: invalid command response")
)

Errors returned when resolving identities.

Functions

This section is empty.

Types

type Channel

type Channel uint8

Channel identifies which MDM channel an enrollment identity belongs to.

const (
	ChannelUnknown Channel = iota
	ChannelDevice
	ChannelUser
	ChannelSharedIPadUser
	ChannelUserEnrollmentDevice
	ChannelUserEnrollmentUser
)

Channels. Apple runs a device channel and, on macOS and shared iPad, a user channel; User Enrollment (BYOD) uses EnrollmentID instead of UDID.

func (Channel) IsUser

func (c Channel) IsUser() bool

IsUser reports whether the channel is a user channel.

func (Channel) String

func (c Channel) String() string

String implements fmt.Stringer.

func (Channel) Valid

func (c Channel) Valid() bool

Valid reports whether the channel is one of the defined values.

type Checkin

type Checkin struct {
	// Type is the MessageType wire value (Authenticate, TokenUpdate, ...).
	Type string
	// Message is the typed message, one of the schema/checkin types.
	Message checkin.Message
	// Enrollment holds the identity keys as sent.
	Enrollment Enrollment
	// ID is the resolved enrollment identity.
	ID EnrollmentID
	// Raw is the plist exactly as received.
	Raw []byte
}

Checkin is a decoded check-in message: the typed message from the generated schema, the identity keys, the resolved enrollment id, and the raw bytes as received.

func DecodeCheckin

func DecodeCheckin(raw []byte, opts ...DecodeOption) (*Checkin, error)

DecodeCheckin parses a check-in request body.

type Command

type Command struct {
	UUID        string
	RequestType string
	// Payload is the typed command when known; nil after decoding a command
	// whose RequestType is not in the schema registry.
	Payload commands.Command
	// Raw is the complete command plist sent to the device.
	Raw []byte
}

Command is a queued MDM command: the envelope Apple documents as {CommandUUID, Command: {RequestType, ...}} plus the typed payload.

func DecodeCommand

func DecodeCommand(raw []byte, opts ...DecodeOption) (*Command, error)

DecodeCommand parses a command plist, resolving the typed payload through the schema registry when the RequestType is known.

func NewCommand

func NewCommand(payload commands.Command, opts ...CommandOption) (*Command, error)

NewCommand builds the wire plist for a typed command, injecting RequestType and a time-ordered UUID.

type CommandOption

type CommandOption func(*Command)

CommandOption configures NewCommand.

func WithUUID

func WithUUID(id string) CommandOption

WithUUID sets an explicit CommandUUID instead of a generated UUIDv7.

type DecodeOption

type DecodeOption func(*decodeOptions)

DecodeOption configures decoding.

func WithLimits

func WithLimits(d plist.Decoder) DecodeOption

WithLimits overrides the plist size and depth limits.

type Enrollment

type Enrollment struct {
	UDID             string `plist:"UDID,omitempty" json:"UDID,omitempty"`
	UserID           string `plist:"UserID,omitempty" json:"UserID,omitempty"`
	UserShortName    string `plist:"UserShortName,omitempty" json:"UserShortName,omitempty"`
	UserLongName     string `plist:"UserLongName,omitempty" json:"UserLongName,omitempty"`
	EnrollmentID     string `plist:"EnrollmentID,omitempty" json:"EnrollmentID,omitempty"`
	EnrollmentUserID string `plist:"EnrollmentUserID,omitempty" json:"EnrollmentUserID,omitempty"`
}

Enrollment carries the identity keys present on every check-in message and command response. Which keys are populated depends on the channel.

func (Enrollment) Resolve

func (en Enrollment) Resolve() (EnrollmentID, error)

Resolve derives the EnrollmentID from the identity keys, following the rules in Apple's check-in documentation:

  • UDID present: device channel keyed by UDID; with UserID it is the user channel "UDID:UserID", or the shared iPad user channel "UDID:UserShortName" when UserID is the shared iPad sentinel.
  • EnrollmentID present (User Enrollment): device channel keyed by EnrollmentID; with EnrollmentUserID it is "EnrollmentID:EnrollmentUserID".

type EnrollmentID

type EnrollmentID struct {
	Channel  Channel
	ID       string
	ParentID string
}

EnrollmentID is the normalised identity of one channel of one enrollment. ID is the UDID or EnrollmentID for device channels and "<device>:<user>" for user channels; ParentID is the device channel id for user channels.

func (EnrollmentID) Device

func (e EnrollmentID) Device() EnrollmentID

Device returns the device-channel identity this id belongs to (itself for device channels).

func (EnrollmentID) String

func (e EnrollmentID) String() string

String returns the id.

func (EnrollmentID) Validate

func (e EnrollmentID) Validate() error

Validate checks the id is well formed.

type ErrorChainItem

type ErrorChainItem struct {
	ErrorCode            int64  `plist:"ErrorCode" json:"ErrorCode"`
	ErrorDomain          string `plist:"ErrorDomain" json:"ErrorDomain"`
	LocalizedDescription string `plist:"LocalizedDescription,omitempty" json:"LocalizedDescription,omitempty"`
	USEnglishDescription string `plist:"USEnglishDescription,omitempty" json:"USEnglishDescription,omitempty"`
}

ErrorChainItem is one entry of the ErrorChain array on an Error response.

type ParseError

type ParseError struct {
	Err     error
	Content []byte
}

ParseError wraps a decode failure with the offending content so callers can log it. Content is bounded by the plist size limits.

func (*ParseError) Error

func (e *ParseError) Error() string

Error implements error.

func (*ParseError) Unwrap

func (e *ParseError) Unwrap() error

Unwrap implements errors.Unwrap.

type PeerInfo

type PeerInfo struct {
	RemoteAddr string
	UserAgent  string
}

PeerInfo describes the transport peer of a request.

type Push

type Push struct {
	Topic string
	Token []byte
	Magic string
}

Push is what the server needs to wake a device: from TokenUpdate.

func PushFromTokenUpdate

func PushFromTokenUpdate(m *checkin.TokenUpdate) (Push, error)

PushFromTokenUpdate extracts push information from a TokenUpdate.

func (Push) Valid

func (p Push) Valid() bool

Valid reports whether all three parts are present.

type Request

type Request struct {
	ID          EnrollmentID
	Enrollment  Enrollment
	Certificate *x509.Certificate
	// Bearer carries account-driven authorization and redacts itself in logs.
	Bearer     secrets.Secret
	Params     map[string]string
	Peer       PeerInfo
	ReceivedAt time.Time
}

Request is the context of one device request handed to the service layer. It never carries a context.Context: every service method takes one.

type Response

type Response struct {
	Enrollment  Enrollment
	ID          EnrollmentID
	CommandUUID string
	Status      Status
	ErrorChain  []ErrorChainItem
	// Payload is the typed response when the caller supplied the RequestType
	// of the command being answered and the status is Acknowledged.
	Payload commands.Response
	Raw     []byte
}

Response is a decoded command response (or an Idle poll).

func DecodeResponse

func DecodeResponse(raw []byte, requestType string, opts ...DecodeOption) (*Response, error)

DecodeResponse parses a command response body. requestType may be empty; when set and the registry knows it, Payload is populated for Acknowledged responses.

func (*Response) IsIdle

func (r *Response) IsIdle() bool

IsIdle reports whether the message is an Idle poll rather than a result.

type Status

type Status string

Status is the Status key of a command response.

const (
	StatusAcknowledged       Status = "Acknowledged"
	StatusError              Status = "Error"
	StatusCommandFormatError Status = "CommandFormatError"
	StatusIdle               Status = "Idle"
	StatusNotNow             Status = "NotNow"
)

Statuses Apple documents for command responses.

func (Status) Valid

func (s Status) Valid() bool

Valid reports whether the status is one Apple defines.

type UserAuthenticateResponse

type UserAuthenticateResponse struct {
	DigestChallenge *string `plist:"DigestChallenge,omitempty" json:"DigestChallenge,omitempty"`
	AuthToken       *string `plist:"AuthToken,omitempty" json:"AuthToken,omitempty"`
}

UserAuthenticateResponse is the server's reply to UserAuthenticate, which Apple documents in prose rather than in the schema: the first reply carries DigestChallenge (empty to skip authentication), the second carries AuthToken (empty to reject the password).

Jump to

Keyboard shortcuts

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