This is Unofficial EPICS BASE Doxygen Site
security.cpp
Go to the documentation of this file.
1 
7 #include <osiProcess.h>
8 
9 #include <epicsThread.h>
10 #include <epicsGuard.h>
11 #include <pv/epicsException.h>
12 #include <pv/reftrack.h>
13 
14 #define epicsExportSharedSymbols
15 #include <pv/securityImpl.h>
16 
18 
19 namespace {
20 namespace pvd = epics::pvData;
21 namespace pva = epics::pvAccess;
22 
23 
24 pvd::StructureConstPtr userAndHostStructure(
26  add("user", pvd::pvString)->
27  add("host", pvd::pvString)->
28  createStructure()
29 );
30 
31 struct SimpleSession : public pva::AuthenticationSession
32 {
33  const pvd::PVStructure::const_shared_pointer initdata;
34 
35  SimpleSession(const pvd::PVStructure::const_shared_pointer& data) :initdata(data) {}
36  virtual ~SimpleSession() {}
37 
38  virtual epics::pvData::PVStructure::const_shared_pointer initializationData() OVERRIDE FINAL
39  { return initdata; }
40 };
41 
42 struct AnonPlugin : public pva::AuthenticationPlugin
43 {
44  const bool server;
45 
46  AnonPlugin(bool server) :server(server) {}
47  virtual ~AnonPlugin() {}
48 
49  virtual std::tr1::shared_ptr<pva::AuthenticationSession> createSession(
50  const std::tr1::shared_ptr<pva::PeerInfo>& peer,
51  std::tr1::shared_ptr<pva::AuthenticationPluginControl> const & control,
52  epics::pvData::PVStructure::shared_pointer const & data) OVERRIDE FINAL
53  {
54  std::tr1::shared_ptr<SimpleSession> sess(new SimpleSession(pvd::PVStructure::const_shared_pointer())); // no init data
55  if(server) {
56  peer->identified = false;
57  peer->account = "anonymous";
58  control->authenticationCompleted(pvd::Status::Ok, peer);
59  }
60  return sess;
61  }
62 };
63 
64 struct CAPlugin : public pva::AuthenticationPlugin
65 {
66  const bool server;
67  // fully const after ctor
68  const pvd::PVStructurePtr user;
69 
70  CAPlugin(bool server)
71  :server(server)
72  ,user(userAndHostStructure->build())
73  {
74  std::vector<char> buffer(256u);
75  if(osiGetUserName(&buffer[0], buffer.size()) != osiGetUserNameSuccess)
76  throw std::runtime_error("Unable to determine user account name");
77 
78  buffer[buffer.size()-1] = '\0';
79  user->getSubFieldT<pvd::PVString>("user")->put(&buffer[0]);
80 
81  // use of unverified host name is considered deprecated.
82  // use PeerInfo::peer instead.
83  if (gethostname(&buffer[0], buffer.size()) != 0)
84  throw std::runtime_error("Unable to determine host name");
85 
86  buffer[buffer.size()-1] = '\0';
87  user->getSubFieldT<pvd::PVString>("host")->put(&buffer[0]);
88  }
89  virtual ~CAPlugin() {}
90 
91  virtual std::tr1::shared_ptr<pva::AuthenticationSession> createSession(
92  const std::tr1::shared_ptr<pva::PeerInfo>& peer,
93  std::tr1::shared_ptr<pva::AuthenticationPluginControl> const & control,
94  epics::pvData::PVStructure::shared_pointer const & data) OVERRIDE FINAL
95  {
96  std::tr1::shared_ptr<SimpleSession> sess(new SimpleSession(user)); // no init data
97  if(server) {
98  pvd::PVString::shared_pointer user;
99  if(data)
100  user = data->getSubField<pvd::PVString>("user");
101 
102  if(user) {
103  peer->account = user->get();
104  peer->identified = !peer->account.empty();
105  peer->aux = pvd::getPVDataCreate()->createPVStructure(data); // clone to ensure it won't be modified
106  }
107  control->authenticationCompleted(pvd::Status::Ok, peer);
108  }
109  return sess;
110  }
111 };
112 
113 struct GroupsPlugin : public pva::AuthorizationPlugin
114 {
115  virtual ~GroupsPlugin() {}
116 
117  void authorize(const std::tr1::shared_ptr<pva::PeerInfo>& peer)
118  {
119  if(!peer->identified)
120  return; // no groups for anonymous
121 
122  pva::osdGetRoles(peer->account, peer->roles);
123  }
124 };
125 
126 } // namespace
127 
128 namespace epics {
129 namespace pvAccess {
130 
131 size_t PeerInfo::num_instances;
132 
133 PeerInfo::PeerInfo()
134  :transportVersion(0u)
135  ,local(false)
136  ,identified(false)
137 {
138  REFTRACE_INCREMENT(num_instances);
139 }
140 
142 {
143  REFTRACE_DECREMENT(num_instances);
144 }
145 
147 
149 
151 
153 
155 
157 
158 namespace {
159 struct authGbl_t {
160  mutable epicsMutex mutex;
161  AuthenticationRegistry servers, clients;
162  AuthorizationRegistry authorizers;
163 } *authGbl;
164 
165 void authGblInit(void *)
166 {
167  authGbl = new authGbl_t;
168 
169  {
170  AnonPlugin::shared_pointer plugin(new AnonPlugin(true));
171  authGbl->servers.add(-1024, "anonymous", plugin);
172  }
173  {
174  AnonPlugin::shared_pointer plugin(new AnonPlugin(false));
175  authGbl->clients.add(-1024, "anonymous", plugin);
176  }
177 
178  {
179  CAPlugin::shared_pointer plugin(new CAPlugin(true));
180  authGbl->servers.add(0, "ca", plugin);
181  }
182  {
183  CAPlugin::shared_pointer plugin(new CAPlugin(false));
184  authGbl->clients.add(0, "ca", plugin);
185  }
186  {
187  GroupsPlugin::shared_pointer plugin(new GroupsPlugin);
188  authGbl->authorizers.add(0, plugin);
189  }
190 
191  epics::registerRefCounter("PeerInfo", &PeerInfo::num_instances);
192 }
193 
195 } // namespace
196 
198 {
199  epicsThreadOnce(&authGblOnce, &authGblInit, 0);
200  assert(authGbl);
201  return authGbl->clients;
202 }
203 
205 {
206  epicsThreadOnce(&authGblOnce, &authGblInit, 0);
207  assert(authGbl);
208  return authGbl->servers;
209 }
210 
212 {
213  plugmap.clear();
214  Guard G(mutex);
215  plugmap.reserve(map.size());
216  for(map_t::const_iterator it(map.begin()), end(map.end()); it!=end; ++it) {
217  plugmap.push_back(it->second);
218  }
219 }
220 
221 void AuthenticationRegistry::add(int prio, const std::string& name,
222  const AuthenticationPlugin::shared_pointer& plugin)
223 {
224  Guard G(mutex);
225  if(map.find(prio)!=map.end())
226  THROW_EXCEPTION2(std::logic_error, "Authentication plugin already registered with this priority");
227  map[prio] = std::make_pair(name, plugin);
228 }
229 
230 bool AuthenticationRegistry::remove(const AuthenticationPlugin::shared_pointer& plugin)
231 {
232  Guard G(mutex);
233  for(map_t::iterator it(map.begin()), end(map.end()); it!=end; ++it) {
234  if(it->second.second==plugin) {
235  map.erase(it);
236  return true;
237  }
238  }
239  return false;
240 }
241 
242 AuthenticationPlugin::shared_pointer AuthenticationRegistry::lookup(const std::string& name) const
243 {
244  Guard G(mutex);
245  // assuming the number of plugins is small, we don't index by name.
246  for(map_t::const_iterator it(map.begin()), end(map.end()); it!=end; ++it) {
247  if(it->second.first==name)
248  return it->second.second;
249  }
250  return AuthenticationPlugin::shared_pointer();
251 }
252 
253 
255  :busy(0)
256 {}
257 
259 {
260  epicsThreadOnce(&authGblOnce, &authGblInit, 0);
261  assert(authGbl);
262  return authGbl->authorizers;
263 }
264 
265 void AuthorizationRegistry::add(int prio, const AuthorizationPlugin::shared_pointer& plugin)
266 {
267  Guard G(mutex);
268  // we don't expect changes after server start
269  if(busy)
270  throw std::runtime_error("AuthorizationRegistry busy");
271  if(map.find(prio)!=map.end())
272  THROW_EXCEPTION2(std::logic_error, "Authorization plugin already registered with this priority");
273  map[prio] = plugin;
274 }
275 
276 bool AuthorizationRegistry::remove(const AuthorizationPlugin::shared_pointer& plugin)
277 {
278  Guard G(mutex);
279  if(busy)
280  throw std::runtime_error("AuthorizationRegistry busy");
281  for(map_t::iterator it(map.begin()), end(map.end()); it!=end; ++it) {
282  if(it->second==plugin) {
283  map.erase(it);
284  return true;
285  }
286  }
287  return false;
288 }
289 
290 void AuthorizationRegistry::run(const std::tr1::shared_ptr<PeerInfo>& peer)
291 {
292  {
293  Guard G(mutex);
294  busy++;
295  }
296  for(map_t::iterator it(map.begin()), end(map.end()); it!=end; ++it)
297  {
298  (it->second)->authorize(peer);
299  }
300  {
301  Guard G(mutex);
302  assert(busy>=0);
303  busy--;
304  }
305 }
306 
308  Transport::shared_pointer const & transport,
309  epics::pvData::int8 version,
310  epics::pvData::int8 command,
311  size_t payloadSize,
312  epics::pvData::ByteBuffer* payloadBuffer)
313 {
314  ResponseHandler::handleResponse(responseFrom, transport, version, command, payloadSize, payloadBuffer);
315 
316  pvd::PVStructure::shared_pointer data;
317  {
318  pvd::PVField::shared_pointer raw(SerializationHelper::deserializeFull(payloadBuffer, transport.get()));
319  if(raw->getField()->getType()==pvd::structure) {
321  } else {
322  // was originally possible, but never used
323  }
324  }
325 
326  transport->authNZMessage(data);
327 }
328 
329 }} // namespace epics::pvAccess
int8_t int8
Definition: pvType.h:75
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
std::tr1::shared_ptr< detail::SharedPut > put
#define THROW_EXCEPTION2(TYPE, MSG)
static Status Ok
Definition: status.h:47
virtual void handleResponse(osiSockAddr *responseFrom, Transport::shared_pointer const &transport, epics::pvData::int8 version, epics::pvData::int8 command, std::size_t payloadSize, epics::pvData::ByteBuffer *payloadBuffer)
Actor through which authentication exchanges are initiated.
Definition: security.h:198
void run(const std::tr1::shared_ptr< PeerInfo > &peer)
Definition: security.cpp:290
shared_ptr< T > static_pointer_cast(shared_ptr< U > const &r) BOOST_NOEXCEPT
Definition: shared_ptr.hpp:788
TODO only here because of the Lockable.
Definition: ntaggregate.cpp:16
std::tr1::shared_ptr< const Structure > StructureConstPtr
Definition: pvIntrospect.h:162
epicsShareFunc void osdGetRoles(const std::string &account, PeerInfo::roles_t &roles)
Query OS specific DB for role/group names assocated with a user account.
Definition: getgroups.cpp:51
void add(int prio, const AuthorizationPlugin::shared_pointer &plugin)
Definition: security.cpp:265
static epics::pvData::PVField::shared_pointer deserializeFull(epics::pvData::ByteBuffer *payloadBuffer, epics::pvData::DeserializableControl *control)
#define OVERRIDE
Definition: pvAccess.h:55
storage_t::arg_type get() const
Definition: pvData.h:396
AuthenticationRegistry servers
Definition: security.cpp:161
bool remove(const AuthenticationPlugin::shared_pointer &plugin)
Remove an existing entry. Remove true if the entry was actually removed.
Definition: security.cpp:230
bool remove(const AuthorizationPlugin::shared_pointer &plugin)
Definition: security.cpp:276
epicsMutex mutex
Definition: security.cpp:160
Holds all PVA related.
Definition: pvif.h:34
PVString is special case, since it implements SerializableArray.
Definition: pvData.h:521
#define EPICS_THREAD_ONCE_INIT
Definition: epicsThread.h:109
static AuthenticationRegistry & servers()
The server side of the conversation.
Definition: security.cpp:204
static size_t num_instances
Definition: security.h:122
pvData
Definition: monitor.h:428
epicsGuard< epicsMutex > Guard
Definition: security.cpp:17
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
void snapshot(list_t &plugmap) const
Save a copy of the current registry in order of increasing priority.
Definition: security.cpp:211
AuthenticationPlugin::shared_pointer lookup(const std::string &name) const
Definition: security.cpp:242
This class implements a Bytebuffer that is like the java.nio.ByteBuffer.
Definition: byteBuffer.h:233
void add(int prio, const std::string &name, const AuthenticationPlugin::shared_pointer &plugin)
Add a new plugin to this registry.
Definition: security.cpp:221
Data interface for a structure,.
Definition: pvData.h:712
void registerRefCounter(const char *name, const size_t *counter)
Definition: reftrack.cpp:59
std::tr1::shared_ptr< PVStructure > PVStructurePtr
Definition: pvData.h:87
virtual void handleResponse(osiSockAddr *responseFrom, Transport::shared_pointer const &transport, epics::pvData::int8 version, epics::pvData::int8 command, size_t payloadSize, epics::pvData::ByteBuffer *payloadBuffer)
Definition: security.cpp:307
LIBCOM_API osiGetUserNameReturn epicsStdCall osiGetUserName(char *pBuf, unsigned bufSizeIn)
Definition: osdProcess.c:33
AuthenticationRegistry clients
Definition: security.cpp:161
AuthorizationRegistry authorizers
Definition: security.cpp:162
static AuthorizationRegistry & plugins()
Definition: security.cpp:258
static AuthenticationRegistry & clients()
The client side of the conversation.
Definition: security.cpp:197
virtual epics::pvData::PVStructure::const_shared_pointer initializationData()
Definition: security.h:160
std::vector< map_t::mapped_type > list_t
Definition: security.h:239
C++ and C descriptions for a thread.
static FieldBuilderPtr begin()
#define false
Definition: flexdef.h:85
FORCE_INLINE const PVDataCreatePtr & getPVDataCreate()
Definition: pvData.h:1648
#define FINAL
Definition: pvAccess.h:48