blob: 6269bc73236e1c72e20fad7436f332c5e6a6917d [file] [log] [blame]
khenaidooffe076b2019-01-15 16:08:08 -05001// Copyright 2016 CoreOS, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// +build cgo
16
17package util
18
19// #include <stdlib.h>
20// #include <sys/types.h>
21// #include <unistd.h>
22//
23// int
24// my_sd_pid_get_owner_uid(void *f, pid_t pid, uid_t *uid)
25// {
26// int (*sd_pid_get_owner_uid)(pid_t, uid_t *);
27//
28// sd_pid_get_owner_uid = (int (*)(pid_t, uid_t *))f;
29// return sd_pid_get_owner_uid(pid, uid);
30// }
31//
32// int
33// my_sd_pid_get_unit(void *f, pid_t pid, char **unit)
34// {
35// int (*sd_pid_get_unit)(pid_t, char **);
36//
37// sd_pid_get_unit = (int (*)(pid_t, char **))f;
38// return sd_pid_get_unit(pid, unit);
39// }
40//
41// int
42// my_sd_pid_get_slice(void *f, pid_t pid, char **slice)
43// {
44// int (*sd_pid_get_slice)(pid_t, char **);
45//
46// sd_pid_get_slice = (int (*)(pid_t, char **))f;
47// return sd_pid_get_slice(pid, slice);
48// }
49//
50// int
51// am_session_leader()
52// {
53// return (getsid(0) == getpid());
54// }
55import "C"
56import (
57 "fmt"
58 "syscall"
59 "unsafe"
60
61 "github.com/coreos/pkg/dlopen"
62)
63
64var libsystemdNames = []string{
65 // systemd < 209
66 "libsystemd-login.so.0",
67 "libsystemd-login.so",
68
69 // systemd >= 209 merged libsystemd-login into libsystemd proper
70 "libsystemd.so.0",
71 "libsystemd.so",
72}
73
74func getRunningSlice() (slice string, err error) {
75 var h *dlopen.LibHandle
76 h, err = dlopen.GetHandle(libsystemdNames)
77 if err != nil {
78 return
79 }
80 defer func() {
81 if err1 := h.Close(); err1 != nil {
82 err = err1
83 }
84 }()
85
86 sd_pid_get_slice, err := h.GetSymbolPointer("sd_pid_get_slice")
87 if err != nil {
88 return
89 }
90
91 var s string
92 sl := C.CString(s)
93 defer C.free(unsafe.Pointer(sl))
94
95 ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl)
96 if ret < 0 {
97 err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret))
98 return
99 }
100
101 return C.GoString(sl), nil
102}
103
104func runningFromSystemService() (ret bool, err error) {
105 var h *dlopen.LibHandle
106 h, err = dlopen.GetHandle(libsystemdNames)
107 if err != nil {
108 return
109 }
110 defer func() {
111 if err1 := h.Close(); err1 != nil {
112 err = err1
113 }
114 }()
115
116 sd_pid_get_owner_uid, err := h.GetSymbolPointer("sd_pid_get_owner_uid")
117 if err != nil {
118 return
119 }
120
121 var uid C.uid_t
122 errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid)
123 serrno := syscall.Errno(-errno)
124 // when we're running from a unit file, sd_pid_get_owner_uid returns
125 // ENOENT (systemd <220), ENXIO (systemd 220-223), or ENODATA
126 // (systemd >=234)
127 switch {
128 case errno >= 0:
129 ret = false
130 case serrno == syscall.ENOENT, serrno == syscall.ENXIO, serrno == syscall.ENODATA:
131 // Since the implementation of sessions in systemd relies on
132 // the `pam_systemd` module, using the sd_pid_get_owner_uid
133 // heuristic alone can result in false positives if that module
134 // (or PAM itself) is not present or properly configured on the
135 // system. As such, we also check if we're the session leader,
136 // which should be the case if we're invoked from a unit file,
137 // but not if e.g. we're invoked from the command line from a
138 // user's login session
139 ret = C.am_session_leader() == 1
140 default:
141 err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno))
142 }
143 return
144}
145
146func currentUnitName() (unit string, err error) {
147 var h *dlopen.LibHandle
148 h, err = dlopen.GetHandle(libsystemdNames)
149 if err != nil {
150 return
151 }
152 defer func() {
153 if err1 := h.Close(); err1 != nil {
154 err = err1
155 }
156 }()
157
158 sd_pid_get_unit, err := h.GetSymbolPointer("sd_pid_get_unit")
159 if err != nil {
160 return
161 }
162
163 var s string
164 u := C.CString(s)
165 defer C.free(unsafe.Pointer(u))
166
167 ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u)
168 if ret < 0 {
169 err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret))
170 return
171 }
172
173 unit = C.GoString(u)
174 return
175}