1 /++ 2 Privilege dropping 3 +/ 4 module socketplate.privdrop; 5 6 import std.typecons : nullable, Nullable; 7 8 @safe nothrow: 9 10 version (Posix) 11 { 12 public import core.sys.posix.sys.types : uid_t, gid_t; 13 14 /// 15 struct Privileges 16 { 17 Nullable!uid_t user; /// 18 Nullable!gid_t group; /// 19 20 /// 21 static bool resolve(string username, string groupname, out Privileges result) 22 { 23 result = Privileges(); 24 25 uid_t uid; 26 gid_t gid; 27 28 if (!resolveUsername(username, uid)) 29 return false; 30 31 if (!resolveGroupname(groupname, gid)) 32 return false; 33 34 result.user = uid; 35 result.group = gid; 36 37 return true; 38 } 39 } 40 41 /// 42 Privileges currentPrivileges() @nogc 43 { 44 import core.sys.posix.unistd; 45 46 return Privileges( 47 nullable(getuid()), 48 nullable(getgid()), 49 ); 50 } 51 52 /// 53 bool resolveUsername(string username, out uid_t result) @trusted 54 { 55 import core.sys.posix.pwd; 56 import std.conv : to; 57 import std.string : fromStringz; 58 59 bool usernameCouldBeUid = true; 60 uid_t usernameNumeric; 61 try 62 usernameNumeric = username.to!uid_t(); 63 catch (Exception) 64 usernameCouldBeUid = false; 65 66 scope (exit) 67 endpwent(); 68 69 for (passwd* db = getpwent(); db !is null; db = getpwent()) 70 { 71 if (db.pw_name.fromStringz != username) 72 { 73 if (!usernameCouldBeUid) 74 continue; 75 76 if (db.pw_uid != usernameNumeric) 77 continue; 78 } 79 80 result = db.pw_uid; 81 return true; 82 } 83 84 return false; 85 } 86 87 /// 88 bool resolveGroupname(string groupname, out gid_t result) @trusted 89 { 90 import core.sys.posix.grp; 91 import std.conv : to; 92 import std.string : toStringz; 93 94 group* g = getgrnam(groupname.toStringz); 95 if (g is null) 96 { 97 gid_t groupnameNumeric; 98 try 99 groupnameNumeric = groupname.to!gid_t; 100 catch (Exception) 101 return false; 102 103 g = getgrgid(groupnameNumeric); 104 105 if (g is null) 106 return false; 107 } 108 109 result = g.gr_gid; 110 return true; 111 } 112 113 /// 114 bool dropPrivileges(Privileges privileges) @nogc 115 { 116 if (!privileges.group.isNull) 117 if (!dropGroup(privileges.group.get)) 118 return false; 119 120 if (!privileges.user.isNull) 121 if (!dropUser(privileges.user.get)) 122 return false; 123 124 return true; 125 } 126 127 private @nogc 128 { 129 bool dropUser(uid_t uid) @trusted 130 { 131 import core.sys.posix.unistd : setuid; 132 133 return (setuid(uid) == 0); 134 } 135 136 bool dropGroup(gid_t uid) @trusted 137 { 138 import core.sys.posix.unistd : setgid; 139 140 return (setgid(uid) == 0); 141 } 142 } 143 }