diff options
Diffstat (limited to 'sd_id128/get.go')
-rw-r--r-- | sd_id128/get.go | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/sd_id128/get.go b/sd_id128/get.go new file mode 100644 index 0000000..d8cdcfa --- /dev/null +++ b/sd_id128/get.go @@ -0,0 +1,152 @@ +// Copyright 2016 Luke Shumaker +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sd_id128 + +import ( + "crypto/rand" + "os" + "strings" +) + +// GetRandomUUID generates a random UUID (122 random bits). +// +// For convenience when a valid UUID is needed, rather than returning +// a totally random 128-bit number, this sets the UUID type +// ("variant") to RFC 4122 format, and the sub-type ("version") to +// "4", which is (pseudo) random generation. This leaves 122 random +// bits. +// +// The pseudorandom number generator used is cryptographically secure. +func GetRandomUUID() (ID128, error) { + var id ID128 + _, err := rand.Read(id[:]) + if err != nil { + return ID128{}, err + } + + // Set the type ("variant") to RFC 4122 format + id[8] = (id[8] & 0x3F) | 0x80 + // Set the sub-type ("version") to 4 (random generation). + id[6] = (id[6] & 0x0F) | 0x40 + + return id, nil +} + +var cachedMachineID ID128 + +// GetMachineID returns a unique identifier for this operating system +// installation. +// +// This is read as a plain hexadecimal number (with an optional +// trailing newline) from "/etc/machine-id". +// +// Note that unlike every other "Get*ID" function, the ID returned by +// GetMachineID is not guaranteed to be a valid UUID, though values +// generated by systemd v30 and later are valid UUIDs. +// +// See machine-id(5) for more information. +// +// machine-id(5): https://www.freedesktop.org/software/systemd/man/machine-id.html +func GetMachineID() (ID128, error) { + if cachedMachineID == (ID128{}) { + str, err := readfile("/etc/machine-id") + if err != nil { + return ID128{}, err + } + id, err := ParsePlain(strings.TrimSuffix(str, "\n")) + if err != nil { + return ID128{}, err + } + if id == (ID128{}) { + return ID128{}, ErrInvalid + } + cachedMachineID = id + } + return cachedMachineID, nil +} + +var cachedBootID ID128 + +// GetBootUUID returns a UUID unique to this boot; it is generated by +// the kernel once very early in the boot process. +// +// This is read as a UUID (with trailing newline) from +// "/proc/sys/kernel/random/boot_id". +// +// It may be relied on that the Linux kernel sets boot_id to a UUID +// with the UUID type ("variant") set to RFC 4122 format, and the +// sub-type ("version") set appropriately. +// +// See random(4) for more information. +// +// random(4): http://man7.org/linux/man-pages/man4/random.4.html +func GetBootUUID() (ID128, error) { + if cachedBootID == (ID128{}) { + str, err := readfile("/proc/sys/kernel/random/boot_id") + if err != nil { + return ID128{}, err + } + id, err := ParseUUID(strings.TrimSuffix(str, "\n")) + if err != nil { + return ID128{}, err + } + cachedBootID = id + } + return cachedBootID, nil +} + +var cachedInvocationID ID128 + +// GetInvocationUUID returns a UUID unique to this invocation of the +// currently executed service. +// +// This is read from the "INVOCATION_ID" environment variable, which +// is expected to be set by the service manager. +// +// It may be relied on that the service manager sets this to a UUID +// with the UUID type ("variant") set to RFC 4122 format, and the +// sub-type ("version") set appropriately. +// +// The error returned is ErrNone if the service manager did not set +// INVOCATION_ID, or ErrInvalid if the value of INVOCATION_ID could +// not be parsed. +// +// See sd_id128_get_invocation(3) for more information. +// +// sd_id128_get_invocation(3): https://www.freedesktop.org/software/systemd/man/sd_id128_get_invocation.html +// +// BUG(lukeshu): GetInvocationUUID uses a mechanism specified by "what +// systemd currently does", rather than a stable specification. +func GetInvocationUUID() (ID128, error) { + // BUG(lukeshu): GetInvocationUUID might logically belong in the + // sd_daemon package, but we defer to the C-language + // libsystemd's placement of sd_id128_get_invocation() in + // sd-id128.h. + if cachedInvocationID == (ID128{}) { + // BUG(lukeshu): GetInvocationUUID should distrust the + // environment in certain situations, similarly to GNU + // libc secure_getenv. + str, have := os.LookupEnv("INVOCATION_ID") + if !have { + return ID128{}, ErrNone + } + t, err := Parse(str) + if err != nil { + return ID128{}, err + } + cachedInvocationID = t + } + return cachedInvocationID, nil +} |