git.fiddlerwoaroof.com
Browse code

CJPM-5223: drop privileges to read totp key

Fixes situations where the user's home directory is mounted via nfs with
root_squash

Ed Langley authored on 15/06/2017 00:26:44
Showing 7 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,25 @@
1
+#ifndef _BECOME_H
2
+#define _BECOME_H
3
+
4
+#include "user.h"
5
+#include "sys_unistd.h"
6
+
7
+class become
8
+{
9
+ private:
10
+    unistd unistd_;
11
+ public:
12
+ become(user user, unistd &unistd) :
13
+    unistd_ (unistd)
14
+    {
15
+        uid_t uid = user.uid();
16
+        unistd_.seteuid(uid);
17
+    }
18
+
19
+    ~become()
20
+    {
21
+        unistd_.seteuid(0);
22
+    }
23
+};
24
+
25
+#endif
0 26
new file mode 100644
... ...
@@ -0,0 +1,66 @@
1
+#include "become.h"
2
+#include "sys_unistd.h"
3
+#include "sys_pwd.h"
4
+#include "user.h"
5
+#include "test_util.h"
6
+
7
+template<class T>
8
+std::shared_ptr<T> share (T *t)
9
+{
10
+    return std::shared_ptr<T> (t);
11
+}
12
+
13
+class mock_unistd : public unistd_ifc
14
+{
15
+private:
16
+    uid_t expected_euid_;
17
+public:
18
+    mutable uid_t actual_uid;
19
+    mock_unistd (uid_t expected_euid)
20
+        : expected_euid_ (expected_euid)
21
+    {}
22
+
23
+    int seteuid (uid_t euid) const override
24
+    {
25
+        actual_uid = euid;
26
+        return euid == expected_euid_ ? 0 : -1;
27
+    }
28
+};
29
+
30
+class fake_user : public user_ifc
31
+{
32
+private:
33
+    uid_t uid_;
34
+public:
35
+    fake_user (uid_t uid) : uid_ (uid)
36
+    {}
37
+    uid_t uid() const override
38
+    {
39
+        return uid_;
40
+    }
41
+};
42
+
43
+int become_calls_seteuid_with_right_arguments ()
44
+{
45
+    uid_t expected_uid = 1000;
46
+    std::shared_ptr<mock_unistd> mock_unistd  = share (new class mock_unistd(expected_uid));
47
+    unistd fake_unistd (mock_unistd);
48
+    user fake_user (share (new class fake_user(expected_uid)));
49
+
50
+    become become_ (fake_user, fake_unistd);
51
+
52
+    check (mock_unistd->actual_uid == expected_uid, "become does not seteuid");
53
+
54
+    succeed();
55
+}
56
+
57
+bool run_tests()
58
+{
59
+    test (become_calls_seteuid_with_right_arguments);
60
+    succeed();
61
+}
62
+
63
+int main (int argc, char *argv[])
64
+{
65
+    return !run_tests();
66
+}
... ...
@@ -76,4 +76,3 @@ dual_control dual_control::create (const dual_control_configuration
76 76
     return dual_control (std::shared_ptr<dual_control_ifc> (new impl (
77 77
                              configuration)));
78 78
 }
79
-
... ...
@@ -46,7 +46,7 @@ dual_control initialize()
46 46
     totp_generator generator = totp_generator (time, code_digits);
47 47
     random_source rand (random_source::create (fstreams));
48 48
     tokens tokens (tokens::create (fstreams, generator, rand));
49
-    validator validator (validator::create (directory, tokens));
49
+    validator validator (validator::create (directory, tokens, unistd));
50 50
     pam pam (pam::create());
51 51
     conversation conversation (conversation::create (pam));
52 52
     sys_syslog sys_syslog (sys_syslog::create());
... ...
@@ -13,6 +13,8 @@
13 13
 #include <vector>
14 14
 
15 15
 #include "validator.h"
16
+#include "become.h"
17
+#include "sys_unistd.h"
16 18
 
17 19
 namespace
18 20
 {
... ...
@@ -21,14 +23,19 @@ class impl : public validator_ifc
21 23
 private:
22 24
     directory directory_;
23 25
     tokens tokens_;
26
+    unistd unistd_;
24 27
 public:
25 28
     impl (const directory &directory,
26
-          const tokens tokens) :
29
+          const tokens tokens,
30
+          const unistd unistd) :
27 31
         directory_ (directory),
28
-        tokens_ (tokens) {}
32
+        tokens_ (tokens),
33
+        unistd_ (unistd)
34
+    {}
29 35
     bool validate (const std::string &requester_user_name,
30 36
                    const std::string &authorizer_user_name,
31
-                   const std::string &token, const std::string &reason) override
37
+                   const std::string &token,
38
+                   const std::string &reason) override
32 39
     {
33 40
         std::vector<user> found_user = directory_.find_user (authorizer_user_name);
34 41
 
... ...
@@ -48,17 +55,19 @@ public:
48 55
             return false;
49 56
         }
50 57
 
51
-        std::string user_token = tokens_.token (found_user[0]);
58
+        auto user_ = found_user[0];
59
+        become become_(user_, unistd_);
60
+
61
+        std::string user_token = tokens_.token (user_);
52 62
         return user_token == token;
53 63
     }
54 64
 };
55 65
 }
56 66
 
57 67
 validator validator::create (const directory &directory,
58
-                             const tokens &tokens)
68
+                             const tokens &tokens,
69
+                             const unistd &unistd)
59 70
 {
60
-    std::shared_ptr<validator_ifc> delegate (new impl (directory,
61
-            tokens));
71
+    std::shared_ptr<validator_ifc> delegate (new impl (directory, tokens, unistd));
62 72
     return validator (delegate);
63 73
 }
64
-
... ...
@@ -18,6 +18,7 @@
18 18
 #include "user.h"
19 19
 #include "token.h"
20 20
 #include "generator.h"
21
+#include "sys_unistd.h"
21 22
 
22 23
 class validator_ifc
23 24
 {
... ...
@@ -50,8 +51,8 @@ public:
50 51
                                     authorizer_token, reason);
51 52
     }
52 53
     static validator create (const directory &directory,
53
-                             const tokens &token_supplier);
54
+                             const tokens &token_supplier,
55
+                             const unistd &unistd);
54 56
 };
55 57
 
56 58
 #endif
57
-
... ...
@@ -16,13 +16,51 @@
16 16
 #include "user.h"
17 17
 #include "test_util.h"
18 18
 #include "token.h"
19
+#include "sys_unistd.h"
20
+
21
+template<class T>
22
+std::shared_ptr<T> share (T *t)
23
+{
24
+    return std::shared_ptr<T> (t);
25
+}
26
+
27
+class mock_unistd : public unistd_ifc
28
+{
29
+private:
30
+    uid_t expected_euid_;
31
+public:
32
+    mutable std::vector<uid_t> actual_uids;
33
+    mock_unistd (uid_t expected_euid)
34
+        : expected_euid_ (expected_euid)
35
+    {}
36
+
37
+    int seteuid (uid_t euid) const override
38
+    {
39
+        actual_uids.push_back(euid);
40
+        return (euid == expected_euid_ || euid == 0) ? 0 : -1;
41
+    }
42
+};
43
+
44
+class fake_user : public user_ifc
45
+{
46
+private:
47
+    uid_t uid_;
48
+public:
49
+    fake_user (uid_t uid) : uid_ (uid)
50
+    {}
51
+    uid_t uid() const override
52
+    {
53
+        return uid_;
54
+    }
55
+};
19 56
 
20 57
 class fake_directory : public directory_ifc
21 58
 {
22 59
 private:
23 60
     std::string user_name_;
61
+    uid_t uid_;
24 62
 public:
25
-    fake_directory (const std::string &user_name) : user_name_ (user_name)
63
+    fake_directory (const std::string &user_name, const uid_t uid = -1) : user_name_ (user_name), uid_ (uid)
26 64
     {
27 65
     }
28 66
     fake_directory() : user_name_ ("_NOT_A_USER") {}
... ...
@@ -32,7 +70,7 @@ public:
32 70
         std::vector<user> result;
33 71
 
34 72
         if (user_name == user_name_) {
35
-            result.push_back (user());
73
+            result.push_back (user(share (new fake_user (uid_))));
36 74
         }
37 75
 
38 76
         return result;
... ...
@@ -52,12 +90,6 @@ public:
52 90
     }
53 91
 };
54 92
 
55
-template<class T>
56
-std::shared_ptr<T> share (T *t)
57
-{
58
-    return std::shared_ptr<T> (t);
59
-}
60
-
61 93
 bool validator_validates()
62 94
 {
63 95
 
... ...
@@ -66,14 +98,20 @@ bool validator_validates()
66 98
     tokens tokens (share (new
67 99
                           fake_tokens (token)));
68 100
     std::string user_name = "msmith";
69
-    directory directory (share (new fake_directory (user_name)));
70
-    validator validator = validator::create (directory, tokens);
101
+
102
+    uid_t expected_uid = 1000;
103
+    directory directory (share (new fake_directory (user_name, expected_uid)));
104
+    std::shared_ptr<mock_unistd> mock_unistd = share (new class mock_unistd(expected_uid));
105
+    class unistd unistd (mock_unistd);
106
+    validator validator = validator::create (directory, tokens, unistd);
107
+    std::vector<uid_t> expected_uids {expected_uid, 0};
71 108
 
72 109
     // when
73 110
     bool actual = validator.validate ("requester", user_name, token, "reason");
74 111
 
75 112
     // then
76 113
     check (actual, "should be valid");
114
+    check (mock_unistd->actual_uids == expected_uids, "should drop permissions");
77 115
     succeed();
78 116
 }
79 117
 
... ...
@@ -85,7 +123,8 @@ bool validator_fails_unknown_user()
85 123
     tokens tokens (share (new
86 124
                           fake_tokens));
87 125
     directory directory (share (new fake_directory));
88
-    validator validator = validator::create (directory, tokens);
126
+    class unistd unistd (share (new unistd_ifc()));
127
+    validator validator = validator::create (directory, tokens, unistd);
89 128
 
90 129
     // when
91 130
     bool actual = validator.validate ("requester", "notuser", token, "reason");
... ...
@@ -103,7 +142,8 @@ bool validator_fails_incorrect_token()
103 142
                           fake_tokens));
104 143
     std::string user_name = "msmith";
105 144
     directory directory (share (new fake_directory (user_name)));
106
-    validator validator = validator::create (directory, tokens);
145
+    class unistd unistd (share (new unistd_ifc()));
146
+    validator validator = validator::create (directory, tokens, unistd);
107 147
 
108 148
     // when
109 149
     bool actual = validator.validate ("requester", user_name, "token",
... ...
@@ -123,7 +163,8 @@ bool validator_fails_with_own_token()
123 163
     directory directory (share (new fake_directory (authorizer_user_name)));
124 164
     tokens tokens (share (new
125 165
                           fake_tokens (authorizer_token)));
126
-    validator validator = validator::create (directory, tokens);
166
+    class unistd unistd (share (new unistd_ifc()));
167
+    validator validator = validator::create (directory, tokens, unistd);
127 168
 
128 169
     // when
129 170
     bool actual = validator.validate (requester_user_name, authorizer_user_name,
... ...
@@ -144,7 +185,8 @@ bool validator_fails_with_unknown_requester()
144 185
     directory directory (share (new fake_directory (authorizer_user_name)));
145 186
     tokens tokens (share (new
146 187
                           fake_tokens (authorizer_token)));
147
-    validator validator = validator::create (directory, tokens);
188
+    class unistd unistd (share (new unistd_ifc()));
189
+    validator validator = validator::create (directory, tokens, unistd);
148 190
 
149 191
     // when
150 192
     bool actual = validator.validate (requester_user_name, authorizer_user_name,
... ...
@@ -165,7 +207,8 @@ bool validator_fails_on_empty_reason()
165 207
     directory directory (share (new fake_directory (authorizer_user_name)));
166 208
     tokens tokens (share (new
167 209
                           fake_tokens (authorizer_token)));
168
-    validator validator = validator::create (directory, tokens);
210
+    class unistd unistd (share (new unistd_ifc()));
211
+    validator validator = validator::create (directory, tokens, unistd);
169 212
 
170 213
     //when
171 214
     bool actual = validator.validate (requester_user_name, authorizer_user_name,
... ...
@@ -191,4 +234,3 @@ int main (int argc, char *argv[])
191 234
 {
192 235
     return !run_tests();
193 236
 }
194
-