1 #include "processing.hpp"
2 
3 #include <iostream>
4 #include <string>
5 
6 bool getWellKnown(
7     const boost::container::flat_map<std::string, std::string>& owners,
8     const std::string& request, std::string& wellKnown)
9 {
10     // If it's already a well known name, just return
11     if (!request.starts_with(":"))
12     {
13         wellKnown = request;
14         return true;
15     }
16 
17     auto it = owners.find(request);
18     if (it == owners.end())
19     {
20         return false;
21     }
22     wellKnown = it->second;
23     return true;
24 }
25 
26 bool needToIntrospect(const std::string& processName,
27                       const AllowDenyList& allowList)
28 {
29     auto inAllowList = std::find_if(allowList.begin(), allowList.end(),
30                                     [&processName](const auto& prefix) {
31                                         return processName.starts_with(prefix);
32                                     }) != allowList.end();
33 
34     return inAllowList;
35 }
36 
37 void processNameChangeDelete(
38     boost::container::flat_map<std::string, std::string>& nameOwners,
39     const std::string& wellKnown, const std::string& oldOwner,
40     InterfaceMapType& interfaceMap, AssociationMaps& assocMaps,
41     sdbusplus::asio::object_server& server)
42 {
43     if (oldOwner.starts_with(":"))
44     {
45         auto it = nameOwners.find(oldOwner);
46         if (it != nameOwners.end())
47         {
48             nameOwners.erase(it);
49         }
50     }
51     // Connection removed
52     InterfaceMapType::iterator pathIt = interfaceMap.begin();
53     while (pathIt != interfaceMap.end())
54     {
55         // If an associations interface is being removed,
56         // also need to remove the corresponding associations
57         // objects and properties.
58         auto ifaces = pathIt->second.find(wellKnown);
59         if (ifaces != pathIt->second.end())
60         {
61             auto assoc = std::find(ifaces->second.begin(), ifaces->second.end(),
62                                    assocDefsInterface);
63             if (assoc != ifaces->second.end())
64             {
65                 removeAssociation(pathIt->first, wellKnown, server, assocMaps);
66             }
67 
68             // Instead of checking if every single path is the endpoint of an
69             // association that needs to be moved to pending, only check when
70             // we own this path as well, which would be because of an
71             // association.
72             if ((pathIt->second.size() == 2) &&
73                 (pathIt->second.find("xyz.openbmc_project.ObjectMapper") !=
74                  pathIt->second.end()))
75             {
76                 // Remove the 2 association D-Bus paths and move the
77                 // association to pending.
78                 moveAssociationToPending(pathIt->first, assocMaps, server);
79             }
80         }
81         pathIt->second.erase(wellKnown);
82         if (pathIt->second.empty())
83         {
84             // If the last connection to the object is gone,
85             // delete the top level object
86             pathIt = interfaceMap.erase(pathIt);
87             continue;
88         }
89         pathIt++;
90     }
91 }
92 
93 void processInterfaceAdded(InterfaceMapType& interfaceMap,
94                            const sdbusplus::message::object_path& objPath,
95                            const InterfacesAdded& intfAdded,
96                            const std::string& wellKnown,
97                            AssociationMaps& assocMaps,
98                            sdbusplus::asio::object_server& server)
99 {
100     auto& ifaceList = interfaceMap[objPath.str];
101 
102     for (const auto& interfacePair : intfAdded)
103     {
104         ifaceList[wellKnown].emplace(interfacePair.first);
105 
106         if (interfacePair.first == assocDefsInterface)
107         {
108             const std::variant<std::vector<Association>>* variantAssociations =
109                 nullptr;
110             for (const auto& interface : interfacePair.second)
111             {
112                 if (interface.first == assocDefsProperty)
113                 {
114                     variantAssociations = &(interface.second);
115                 }
116             }
117             if (variantAssociations == nullptr)
118             {
119                 std::cerr << "Illegal association found on " << wellKnown
120                           << "\n";
121                 continue;
122             }
123             std::vector<Association> associations =
124                 std::get<std::vector<Association>>(*variantAssociations);
125             associationChanged(server, associations, objPath.str, wellKnown,
126                                interfaceMap, assocMaps);
127         }
128     }
129 
130     // To handle the case where an object path is being created
131     // with 2 or more new path segments, check if the parent paths
132     // of this path are already in the interface map, and add them
133     // if they aren't with just the default freedesktop interfaces.
134     // This would be done via introspection if they would have
135     // already existed at startup.  While we could also introspect
136     // them now to do the work, we know there aren't any other
137     // interfaces or we would have gotten signals for them as well,
138     // so take a shortcut to speed things up.
139     //
140     // This is all needed so that mapper operations can be done
141     // on the new parent paths.
142     using iface_map_iterator = InterfaceMapType::iterator;
143     using name_map_iterator = InterfaceMapType::mapped_type::iterator;
144 
145     static const InterfaceNames defaultIfaces{
146         "org.freedesktop.DBus.Introspectable", "org.freedesktop.DBus.Peer",
147         "org.freedesktop.DBus.Properties"};
148 
149     std::string parent = objPath.str;
150     auto pos = parent.find_last_of('/');
151 
152     while (pos != std::string::npos)
153     {
154         parent = parent.substr(0, pos);
155 
156         std::pair<iface_map_iterator, bool> parentEntry =
157             interfaceMap.try_emplace(parent);
158 
159         std::pair<name_map_iterator, bool> ifaceEntry =
160             parentEntry.first->second.try_emplace(wellKnown, defaultIfaces);
161 
162         if (!ifaceEntry.second)
163         {
164             // Entry was already there for this name so done.
165             break;
166         }
167 
168         pos = parent.find_last_of('/');
169     }
170 
171     // The new interface might have an association pending
172     checkIfPendingAssociation(objPath.str, interfaceMap, assocMaps, server);
173 }
174