Line |
Branch |
Exec |
Source |
1 |
|
|
/** |
2 |
|
|
* This file is part of the CernVM File System. |
3 |
|
|
*/ |
4 |
|
|
|
5 |
|
|
#ifndef CVMFS_AUTHZ_AUTHZ_FETCH_H_ |
6 |
|
|
#define CVMFS_AUTHZ_AUTHZ_FETCH_H_ |
7 |
|
|
|
8 |
|
|
#include <inttypes.h> |
9 |
|
|
#include <pthread.h> |
10 |
|
|
#include <unistd.h> |
11 |
|
|
|
12 |
|
|
#include <string> |
13 |
|
|
|
14 |
|
|
#include "authz/authz.h" |
15 |
|
|
#include "gtest/gtest_prod.h" |
16 |
|
|
#include "json_document.h" |
17 |
|
|
#include "util/single_copy.h" |
18 |
|
|
|
19 |
|
|
class OptionsManager; |
20 |
|
|
|
21 |
|
|
class AuthzFetcher { |
22 |
|
|
public: |
23 |
|
|
struct QueryInfo { |
24 |
|
8 |
QueryInfo(pid_t p, uid_t u, gid_t g, const std::string &m) |
25 |
|
8 |
: pid(p), uid(u), gid(g), membership(m) { } |
26 |
|
|
pid_t pid; |
27 |
|
|
uid_t uid; |
28 |
|
|
gid_t gid; |
29 |
|
|
std::string membership; |
30 |
|
|
}; |
31 |
|
|
|
32 |
|
112 |
virtual ~AuthzFetcher() { } |
33 |
|
|
|
34 |
|
|
/** |
35 |
|
|
* Based on the given pid, uid, gid and the given membership requirement, |
36 |
|
|
* gather credentials. Positive and negative replies have a time to live. |
37 |
|
|
*/ |
38 |
|
|
virtual AuthzStatus Fetch(const QueryInfo &query_info, |
39 |
|
|
AuthzToken *authz_token, |
40 |
|
|
unsigned *ttl) = 0; |
41 |
|
|
}; |
42 |
|
|
|
43 |
|
|
|
44 |
|
|
/** |
45 |
|
|
* Defines the result on construction. Used in libcvmfs and for testing. |
46 |
|
|
*/ |
47 |
|
|
class AuthzStaticFetcher : public AuthzFetcher { |
48 |
|
|
public: |
49 |
|
|
AuthzStaticFetcher(AuthzStatus s, unsigned ttl) : status_(s), ttl_(ttl) { } |
50 |
|
|
virtual ~AuthzStaticFetcher() { } |
51 |
|
|
virtual AuthzStatus Fetch(const QueryInfo &query_info, |
52 |
|
|
AuthzToken *authz_token, |
53 |
|
|
unsigned *ttl) |
54 |
|
|
{ |
55 |
|
|
*authz_token = AuthzToken(); |
56 |
|
|
*ttl = ttl_; |
57 |
|
|
return status_; |
58 |
|
|
} |
59 |
|
|
|
60 |
|
|
private: |
61 |
|
|
AuthzStatus status_; |
62 |
|
|
unsigned ttl_; |
63 |
|
|
}; |
64 |
|
|
|
65 |
|
|
|
66 |
|
|
/** |
67 |
|
|
* Types of messages that can be sent between cvmfs client and authz helper. |
68 |
|
|
*/ |
69 |
|
|
enum AuthzExternalMsgIds { |
70 |
|
|
kAuthzMsgHandshake = 0, ///< Cvmfs: "Hello, helper, are you there?" |
71 |
|
|
kAuthzMsgReady, ///< Helper: "Yes, cvmfs, I'm here" |
72 |
|
|
kAuthzMsgVerify, ///< Cvmfs: "Please verify, helper" |
73 |
|
|
kAuthzMsgPermit, ///< Helper: "I verified, cvmfs, here's the result" |
74 |
|
|
kAuthzMsgQuit, ///< Cvmfs: "Please shutdown, helper" |
75 |
|
|
kAuthzMsgInvalid ///< First invalid message id |
76 |
|
|
}; |
77 |
|
|
|
78 |
|
|
|
79 |
|
|
/** |
80 |
|
|
* A binary representation of JSON messages that can be received from an authz |
81 |
|
|
* helper. Holds either a kAuthzMsgReady or a kAuthzMsgPermit message. |
82 |
|
|
*/ |
83 |
|
|
struct AuthzExternalMsg { |
84 |
|
|
AuthzExternalMsgIds msgid; |
85 |
|
|
int protocol_revision; |
86 |
|
|
struct { |
87 |
|
|
AuthzStatus status; |
88 |
|
|
AuthzToken token; |
89 |
|
|
uint32_t ttl; |
90 |
|
|
} permit; |
91 |
|
|
}; |
92 |
|
|
|
93 |
|
|
|
94 |
|
|
/** |
95 |
|
|
* Connects to an external process that fetches the tokens. The external helper |
96 |
|
|
* is spawned on demand through execve. It has to receive commands on stdin |
97 |
|
|
* and write replies to stdout. Environment variables of the form |
98 |
|
|
* CVMFS_AUTHZ_... are forwarded to the helper having the CVMFS_AUTHZ_ prefix |
99 |
|
|
* stripped. |
100 |
|
|
*/ |
101 |
|
|
class AuthzExternalFetcher : public AuthzFetcher, SingleCopy { |
102 |
|
|
FRIEND_TEST(T_AuthzFetch, ExecHelper); |
103 |
|
|
FRIEND_TEST(T_AuthzFetch, ExecHelperSlow); |
104 |
|
|
FRIEND_TEST(T_AuthzFetch, ParseMsg); |
105 |
|
|
FRIEND_TEST(T_AuthzFetch, Handshake); |
106 |
|
|
|
107 |
|
|
public: |
108 |
|
|
/** |
109 |
|
|
* The "wire" protocol: 4 byte version, 4 byte length, JSON message. Must |
110 |
|
|
* be the same for cvmfs and helper. |
111 |
|
|
*/ |
112 |
|
|
static const uint32_t kProtocolVersion; // = 1; |
113 |
|
|
|
114 |
|
|
AuthzExternalFetcher(const std::string &fqrn, |
115 |
|
|
const std::string &progname, |
116 |
|
|
const std::string &search_path, |
117 |
|
|
OptionsManager *options_manager); |
118 |
|
|
AuthzExternalFetcher(const std::string &fqrn, int fd_send, int fd_recv); |
119 |
|
|
virtual ~AuthzExternalFetcher(); |
120 |
|
|
|
121 |
|
|
virtual AuthzStatus Fetch(const QueryInfo &query_info, |
122 |
|
|
AuthzToken *authz_token, |
123 |
|
|
unsigned *ttl); |
124 |
|
|
|
125 |
|
|
private: |
126 |
|
|
/** |
127 |
|
|
* After 5 seconds of unresponsiveness, helper processes may be killed. |
128 |
|
|
*/ |
129 |
|
|
static const unsigned kChildTimeout = 5; |
130 |
|
|
|
131 |
|
|
/** |
132 |
|
|
* For now we allow "no caching". |
133 |
|
|
*/ |
134 |
|
|
static const int kMinTtl; // = 0 |
135 |
|
|
|
136 |
|
|
/** |
137 |
|
|
* If permits come without TTL, use 2 minutes. |
138 |
|
|
*/ |
139 |
|
|
static const unsigned kDefaultTtl = 120; |
140 |
|
|
|
141 |
|
|
void InitLock(); |
142 |
|
|
std::string FindHelper(const std::string &membership); |
143 |
|
|
void ExecHelper(); |
144 |
|
|
bool Handshake(); |
145 |
|
|
|
146 |
|
|
bool Send(const std::string &msg); |
147 |
|
|
bool Recv(std::string *msg); |
148 |
|
|
void EnterFailState(); |
149 |
|
|
|
150 |
|
|
void StripAuthzSchema(const std::string &membership, |
151 |
|
|
std::string *authz_schema, |
152 |
|
|
std::string *pure_membership); |
153 |
|
|
bool ParseMsg(const std::string &json_msg, |
154 |
|
|
const AuthzExternalMsgIds expected_msgid, |
155 |
|
|
AuthzExternalMsg *binary_msg); |
156 |
|
|
bool ParseMsgId(JSON *json_authz, AuthzExternalMsg *binary_msg); |
157 |
|
|
bool ParseRevision(JSON *json_authz, AuthzExternalMsg *binary_msg); |
158 |
|
|
bool ParsePermit(JSON *json_authz, AuthzExternalMsg *binary_msg); |
159 |
|
|
|
160 |
|
|
void ReapHelper(); |
161 |
|
|
|
162 |
|
|
/** |
163 |
|
|
* The fully qualified repository name, e.g. atlas.cern.ch |
164 |
|
|
*/ |
165 |
|
|
std::string fqrn_; |
166 |
|
|
|
167 |
|
|
/** |
168 |
|
|
* Full path of external helper. |
169 |
|
|
*/ |
170 |
|
|
std::string progname_; |
171 |
|
|
|
172 |
|
|
/** |
173 |
|
|
* Where to look for authz helpers that are guessed from the membership schema |
174 |
|
|
*/ |
175 |
|
|
std::string search_path_; |
176 |
|
|
|
177 |
|
|
/** |
178 |
|
|
* Send requests to the external helper. |
179 |
|
|
*/ |
180 |
|
|
int fd_send_; |
181 |
|
|
|
182 |
|
|
/** |
183 |
|
|
* Receive authz status, ttl, and token from the external helper. |
184 |
|
|
*/ |
185 |
|
|
int fd_recv_; |
186 |
|
|
|
187 |
|
|
/** |
188 |
|
|
* If a helper was started, the pid must be collected to avoid a zombie. |
189 |
|
|
*/ |
190 |
|
|
pid_t pid_; |
191 |
|
|
|
192 |
|
|
/** |
193 |
|
|
* If the external helper behaves unexectely, enter fail state and stop |
194 |
|
|
* authenticating |
195 |
|
|
*/ |
196 |
|
|
bool fail_state_; |
197 |
|
|
|
198 |
|
|
/** |
199 |
|
|
* Used to gather CVMFS_AUTHZ_ options |
200 |
|
|
*/ |
201 |
|
|
OptionsManager *options_manager_; |
202 |
|
|
|
203 |
|
|
/** |
204 |
|
|
* The send-receive cycle is atomic. |
205 |
|
|
*/ |
206 |
|
|
pthread_mutex_t lock_; |
207 |
|
|
|
208 |
|
|
/** |
209 |
|
|
* After the helper process fails, this is set to the time when it should |
210 |
|
|
* be restarted. |
211 |
|
|
*/ |
212 |
|
|
uint64_t next_start_; |
213 |
|
|
}; |
214 |
|
|
|
215 |
|
|
#endif // CVMFS_AUTHZ_AUTHZ_FETCH_H_ |
216 |
|
|
|