forked from aws/aws-lambda-runtime-interface-emulator
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathuser.go
More file actions
119 lines (111 loc) · 3.53 KB
/
user.go
File metadata and controls
119 lines (111 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// User utilities to create UNIX users and drop root privileges
package main
import (
"fmt"
log "github.com/sirupsen/logrus"
"os"
"os/user"
"strconv"
"strings"
"syscall"
)
// AddUser adds a UNIX user (e.g., sbx_user1051) to the passwd and shadow files if not already present
// The actual default values are based on inspecting the AWS Lambda runtime in us-east-1
// /etc/group is empty and /etc/gshadow is not accessible in AWS
// The home directory does not exist in AWS Lambda
func AddUser(user string, uid int, gid int) {
// passwd file format: https://www.cyberciti.biz/faq/understanding-etcpasswd-file-format/
passwdFile := "/etc/passwd"
passwdEntry := fmt.Sprintf("%[1]s:x:%[2]v:%[3]v::/home/%[1]s:/sbin/nologin", user, uid, gid)
if !doesFileContainEntry(passwdFile, passwdEntry) {
addEntry(passwdFile, passwdEntry)
}
// shadow file format: https://www.cyberciti.biz/faq/understanding-etcshadow-file/
shadowFile := "/etc/shadow"
shadowEntry := fmt.Sprintf("%s:*:18313:0:99999:7:::", user)
if !doesFileContainEntry(shadowFile, shadowEntry) {
addEntry(shadowFile, shadowEntry)
}
}
// doesFileContainEntry returns true if the entry string exists in the given file
func doesFileContainEntry(file string, entry string) bool {
data, err := os.ReadFile(file)
if err != nil {
log.Warnln("Could not read file:", file, err)
return false
}
text := string(data)
return strings.Contains(text, entry)
}
// addEntry appends an entry string to the given file
func addEntry(file string, entry string) error {
f, err := os.OpenFile(file,
os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Errorln("Error opening file:", file, err)
return err
}
defer f.Close()
if _, err := f.WriteString(entry); err != nil {
log.Errorln("Error appending entry to file:", file, err)
return err
}
return nil
}
// IsRootUser returns true if the current process is root and false otherwise.
func IsRootUser() bool {
return os.Getuid() == 0
}
// UserLogger returns a context logger with user fields.
func UserLogger() *log.Entry {
// Skip user lookup at debug level
if !log.IsLevelEnabled(log.DebugLevel) {
return log.WithFields(log.Fields{})
}
uid := os.Getuid()
uidString := strconv.Itoa(uid)
user, err := user.LookupId(uidString)
if err != nil {
log.Warnln("Could not look up user by uid:", uid, err)
}
return log.WithFields(log.Fields{
"username": user.Username,
"uid": uid,
"euid": os.Geteuid(),
"gid": os.Getgid(),
})
}
// DropPrivileges switches to another UNIX user by dropping root privileges
// Initially based on https://stackoverflow.com/a/75545491/6875981
func DropPrivileges(userToSwitchTo string) error {
// Lookup user and group IDs for the user we want to switch to.
userInfo, err := user.Lookup(userToSwitchTo)
if err != nil {
log.Errorln("Error looking up user:", userToSwitchTo, err)
return err
}
// Convert group ID and user ID from string to int.
gid, err := strconv.Atoi(userInfo.Gid)
if err != nil {
log.Errorln("Error converting gid:", userInfo.Gid, err)
return err
}
uid, err := strconv.Atoi(userInfo.Uid)
if err != nil {
log.Errorln("Error converting uid:", userInfo.Uid, err)
return err
}
// Limitation: Debugger gets stuck when stepping over these syscalls!
// No breakpoints beyond this point are hit.
// Set group ID (real and effective).
if err = syscall.Setgid(gid); err != nil {
log.Errorln("Failed to set group ID:", err)
return err
}
// Set user ID (real and effective).
if err = syscall.Setuid(uid); err != nil {
log.Errorln("Failed to set user ID:", err)
return err
}
return nil
}