Corrected logic of checking ownerToken
[accounts-sso:vitalyrepins-signon.git] / src / signond / accesscontrolmanager.cpp
1 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of signon
4  *
5  * Copyright (C) 2009-2010 Nokia Corporation.
6  *
7  * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
8  * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * version 2.1 as published by the Free Software Foundation.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  */
24
25 #include <QBuffer>
26 #include <QDBusConnection>
27 #include <QDBusConnectionInterface>
28
29 #include "accesscontrolmanager.h"
30 #include "signond-common.h"
31 #include "credentialsaccessmanager.h"
32 #include "signonidentity.h"
33
34
35 #define SSO_AEGIS_PACKAGE_ID_TOKEN_PREFIX QLatin1String("AID::")
36 #define SSO_DEFAULT_CREDS_STR_BUFFER_SIZE 256
37
38 #ifdef SIGNON_DISABLE_ACCESS_CONTROL
39 #define RETURN_IF_AC_DISABLED(val)  return (val)
40 #else
41 #define RETURN_IF_AC_DISABLED(val)
42 #endif
43
44 namespace SignonDaemonNS {
45
46     static const char keychainToken[] = "signond::keychain-access";
47
48     bool AccessControlManager::isPeerAllowedToUseIdentity(const QDBusContext &peerContext,
49                                                           const quint32 identityId)
50     {
51         RETURN_IF_AC_DISABLED(true);
52
53         // TODO - improve this, the error handling and more precise behaviour
54
55         CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
56         if (db == 0) {
57             TRACE() << "NULL db pointer, secure storage might be unavailable,";
58             return false;
59         }
60         QStringList acl = db->accessControlList(identityId);
61
62         TRACE() << QString(QLatin1String("Access control list of identity: "
63                                          "%1: [%2].Tokens count: %3\t"))
64             .arg(identityId)
65             .arg(acl.join(QLatin1String(", ")))
66             .arg(acl.size());
67
68         if (db->errorOccurred())
69             return false;
70
71         if (acl.isEmpty())
72             return true;
73
74         return peerHasOneOfTokens(peerContext, acl);
75     }
76
77     AccessControlManager::IdentityOwnership AccessControlManager::isPeerOwnerOfIdentity(
78                                                                        const QDBusContext &peerContext,
79                                                                        const quint32 identityId)
80     {
81         RETURN_IF_AC_DISABLED(ApplicationIsOwner);
82
83         CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
84         if (db == 0) {
85             TRACE() << "NULL db pointer, secure storage might be unavailable,";
86             return ApplicationIsNotOwner;
87         }
88         QString ownerToken = db->credentialsOwnerSecurityToken(identityId);
89
90         if (db->errorOccurred())
91             return ApplicationIsNotOwner;
92
93         if (ownerToken.isNull())
94             return IdentityDoesNotHaveOwner;
95
96         QStringList acl = accessTokens(peerContext);
97         return acl.contains(ownerToken) ? ApplicationIsOwner : ApplicationIsNotOwner;
98     }
99
100     bool AccessControlManager::isPeerKeychainWidget(const QDBusContext &peerContext)
101     {
102         RETURN_IF_AC_DISABLED(true);
103
104         static QString keychainWidgetToken = QLatin1String(keychainToken);
105         return peerHasToken(peerContext, keychainWidgetToken);
106     }
107
108     QString AccessControlManager::idTokenOfPeer(const QDBusContext &peerContext)
109     {
110         RETURN_IF_AC_DISABLED(QString());
111
112         QStringList peerTokens = accessTokens(peerContext);
113         foreach(QString token, peerTokens) {
114             if (token.startsWith(SSO_AEGIS_PACKAGE_ID_TOKEN_PREFIX))
115                 return token;
116         }
117         return QString();
118     }
119
120     QString AccessControlManager::idTokenOfPid(pid_t pid)
121     {
122         RETURN_IF_AC_DISABLED(QString());
123
124         QStringList peerTokens = accessTokens(pid);
125         foreach(QString token, peerTokens) {
126             if (token.startsWith(SSO_AEGIS_PACKAGE_ID_TOKEN_PREFIX))
127                 return token;
128         }
129         return QString();
130     }
131
132     bool AccessControlManager::peerHasOneOfTokens(const QDBusContext &peerContext,
133                                                   const QStringList &tokens)
134     {
135         QStringList peerTokens = accessTokens(peerContext);
136
137         TRACE() << peerTokens << " vs. " << tokens;
138
139         foreach(QString token, tokens)
140             if (peerTokens.contains(token))
141                 return true;
142
143         BLAME() << "given peer does not have needed permissions";
144
145
146         /*
147          * TODO: remove this later, as soon as NB#196033 will be resolved
148          * */
149         if (1)
150             return true;
151
152         return false;
153     }
154
155     QStringList AccessControlManager::accessTokens(const pid_t peerPid)
156     {
157         creds_t ccreds = creds_gettask(peerPid);
158
159         creds_value_t value;
160         creds_type_t type;
161         QStringList tokens;
162
163         char buf[SSO_DEFAULT_CREDS_STR_BUFFER_SIZE];
164         for (int i = 0; (type = creds_list(ccreds, i,  &value)) != CREDS_BAD; ++i) {
165             long actualSize = creds_creds2str(type, value, buf, SSO_DEFAULT_CREDS_STR_BUFFER_SIZE);
166
167             if (actualSize >= SSO_DEFAULT_CREDS_STR_BUFFER_SIZE) {
168                 qWarning() << "Size limit exceeded for aegis token as string.";
169                 buf[SSO_DEFAULT_CREDS_STR_BUFFER_SIZE-1] = 0;
170             } else {
171                 buf[actualSize] = 0;
172             }
173
174             tokens << QString(QString::fromLatin1(buf));
175         }
176
177         creds_free(ccreds);
178         return tokens;
179     }
180
181     QStringList AccessControlManager::accessTokens(const QDBusContext &peerContext)
182     {
183         return accessTokens(pidOfPeer(peerContext));
184     }
185
186     bool AccessControlManager::peerHasToken(const QDBusContext &context, const QString &token)
187     {
188         return peerHasToken(pidOfPeer(context), token);
189     }
190
191     bool AccessControlManager::peerHasToken(const pid_t processPid, const QString &token)
192     {
193         creds_type_t require_type;
194         creds_value_t require_value;
195         creds_t ccreds;
196
197         /* Translate credential string into binary */
198         require_type = creds_str2creds(token.toUtf8().data(), &require_value);
199         if (require_type == CREDS_BAD) {
200             TRACE() << "The string " << token << " does not translate into credentials value";
201             return false;
202         }
203
204         ccreds = creds_gettask(processPid);
205         bool hasAccess = creds_have_p(ccreds, require_type, require_value);
206
207         TRACE() << "Process ACCESS:" << (hasAccess ? "TRUE" : "FALSE");
208         creds_free(ccreds);
209
210         return hasAccess;
211     }
212
213     pid_t AccessControlManager::pidOfPeer(const QDBusContext &peerContext)
214     {
215         QString service = peerContext.message().service();
216         return peerContext.connection().interface()->servicePid(service).value();
217     }
218
219     void AccessControlManager::listCredentials(QIODevice *device, creds_t creds, const QString &ownerInfo)
220     {
221         //TODO - this method will have to disappear at some point.
222         if (!device)
223             return;
224
225         if (!device->isOpen())
226             device->open(QIODevice::WriteOnly);
227
228         device->reset();
229
230         if (!ownerInfo.isNull())
231            device->write(ownerInfo.toUtf8().data(), strlen(ownerInfo.toUtf8().data()));
232
233         creds_value_t value;
234         creds_type_t type;
235
236         device->write("\n");
237
238         char buf[SSO_DEFAULT_CREDS_STR_BUFFER_SIZE];
239         for (int i = 0; (type = creds_list(creds, i,  &value)) != CREDS_BAD; ++i) {
240             long actualSize = creds_creds2str(type, value, buf, SSO_DEFAULT_CREDS_STR_BUFFER_SIZE);
241
242             if (actualSize >= SSO_DEFAULT_CREDS_STR_BUFFER_SIZE) {
243                 qWarning() << "Size limit exceeded for aegis token as string.";
244                 buf[SSO_DEFAULT_CREDS_STR_BUFFER_SIZE-1] = 0;
245             } else {
246                 buf[actualSize] = 0;
247             }
248
249             device->write("\t");
250             device->write(buf, strlen(buf));
251             device->write("\n");
252         }
253         device->write("\n");
254         device->close();
255     }
256 } //namespace SignonDaemonNS