Add dpm auth policy
[platform/core/security/dpm-auth.git] / plugin / password.cpp
1 /*
2  *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  */
16
17 #include <sys/types.h>
18
19 #include <unordered_map>
20
21 #include <dpm/pil/policy-context.h>
22 #include <dpm/pil/policy-model.h>
23 #include <dpm/pil/policy-storage.h>
24 #include <dpm/pil/app-bundle.h>
25 #include <dpm/pil/launchpad.h>
26
27 #include "password-manager.h"
28
29 typedef enum {
30         DPM_PASSWORD_QUALITY_UNSPECIFIED     = 0x00,    /**< No requirements for password. */
31         DPM_PASSWORD_QUALITY_SIMPLE_PASSWORD = 0x01,    /**< Eas requirement for simple password */
32         DPM_PASSWORD_QUALITY_SOMETHING       = 0x10,    /**< Some kind password is required, but doesn't care what it is */
33         DPM_PASSWORD_QUALITY_NUMERIC         = 0x20,    /**< Containing at least numeric characters */
34         DPM_PASSWORD_QUALITY_ALPHABETIC      = 0x40,    /**< Containing at least alphabetic (or other symbol) characters */
35         DPM_PASSWORD_QUALITY_ALPHANUMERIC    = 0x80,    /**< Containing at least numeric and alphabetic characters */
36 } PasswordPolicyQuality;
37
38 typedef enum {
39         DPM_PASSWORD_STATUS_NORMAL,                  /**< Password normal status */
40         DPM_PASSWORD_STATUS_CHANGED,                 /**< Password successfully changed */
41         DPM_PASSWORD_STATUS_NOT_CHANGED,             /**< Password not changed */
42         DPM_PASSWORD_STATUS_CHANGE_REQUIRED ,        /**< Password change required */
43         DPM_PASSWORD_STATUS_MAX_ATTEMPTS_EXCEEDED,   /**< Password Max Attempts Exceeded*/
44
45         DPM_PASSWORD_STATUS_EXPIRED,                    /**< Password expired */
46         DPM_PASSWORD_STATUS_RECOVERY_PASSWORD_FAILED,   /**< Device unlock failed by Password Recovery */
47         DPM_PASSWORD_STATUS_RECOVERY_PASSWORD_SUCCEEDED,/**< Device unlock succeeded by Password Recovery */
48
49         DPM_PASSWORD_STATUS_QUALITY_CHANGED,            /**< Password quality successfully changed */
50         DPM_PASSWORD_STATUS_MIN_LENGTH_CHANGED,         /**< Password min_length successfully changed */
51         DPM_PASSWORD_STATUS_COMPLEX_CHAR_CHANGED,       /**< Password complex_char successfully changed */
52         DPM_PASSWORD_STATUS_PATTERN_CHANGED,            /**< Password pattern successfully changed */
53         DPM_PASSWORD_STATUS_MAX
54 } PasswordPolicyStatus;
55
56 namespace {
57
58 const int simplePasswordLength = 4;
59 const int infinite = 32767;
60
61 std::unordered_map<uid_t, int> passwordStatus;
62
63 inline int inverse(int value)
64 {
65         return -value;
66 }
67
68 inline PasswordManager::QualityType getPasswordQualityType(int quality)
69 {
70         switch (quality) {
71         case DPM_PASSWORD_QUALITY_UNSPECIFIED:
72                 return AUTH_PWD_QUALITY_UNSPECIFIED;
73         case DPM_PASSWORD_QUALITY_SIMPLE_PASSWORD:
74                 return AUTH_PWD_QUALITY_UNSPECIFIED;
75         case DPM_PASSWORD_QUALITY_SOMETHING:
76                 return AUTH_PWD_QUALITY_SOMETHING;
77         case DPM_PASSWORD_QUALITY_NUMERIC:
78                 return AUTH_PWD_QUALITY_NUMERIC;
79         case DPM_PASSWORD_QUALITY_ALPHABETIC:
80                 return AUTH_PWD_QUALITY_ALPHABETIC;
81         case DPM_PASSWORD_QUALITY_ALPHANUMERIC:
82                 return AUTH_PWD_QUALITY_ALPHANUMERIC;
83         default:
84                 throw runtime::Exception("Unknown quality type: " + std::to_string(quality));
85         }
86 }
87
88 } // namespace
89
90 class PasswordQuality : public DomainPolicy<DataSetInt> {
91 public:
92         PasswordQuality() : DomainPolicy("password-quality")
93         {
94         }
95
96         bool apply(const DataType& value, uid_t domain)
97         {
98                 try {
99                         int auth = DPM_PASSWORD_QUALITY_UNSPECIFIED;
100
101                         int quality = inverse(value);
102                         if (quality & DPM_PASSWORD_QUALITY_SIMPLE_PASSWORD) {
103                                 auth = quality - DPM_PASSWORD_QUALITY_SIMPLE_PASSWORD;
104                         }
105
106                         PasswordManager::QualityType type = getPasswordQualityType(auth);
107
108                         PasswordManager passwordManager(domain);
109                         passwordManager.setQuality(type);
110                         passwordManager.enforce();
111                 } catch (runtime::Exception &e) {
112                         ERROR(e.what());
113                         return false;
114                 }
115
116                 return true;
117         }
118 };
119
120 class PasswordSequences : public DomainPolicy<DataSetInt> {
121 public:
122         PasswordSequences() : DomainPolicy("password-numeric-sequences-length")
123         {
124         }
125
126         bool apply(const DataType& value, uid_t domain)
127         {
128                 int v = value;
129                 try {
130                         v = v == infinite ? 0 : v;
131                         PasswordManager passwordManager(domain);
132                         passwordManager.setMaximumNumericSequenceLength(v);
133                         passwordManager.enforce();
134                 } catch (runtime::Exception &e) {
135                         ERROR(e.what());
136                         return false;
137                 }
138
139                 return true;
140         }
141 };
142
143 class PasswordOccurrences : public DomainPolicy<DataSetInt> {
144 public:
145         PasswordOccurrences() : DomainPolicy("password-maximum-character-occurrences")
146         {
147         }
148
149         bool apply(const DataType& value, uid_t domain)
150         {
151                 int v = value;
152                 try {
153                         v = v == infinite ? 0 : v;
154                         PasswordManager passwordManager(domain);
155                         passwordManager.setMaximumCharacterOccurrences(value);
156                         passwordManager.enforce();
157                 } catch (runtime::Exception &e) {
158                         ERROR(e.what());
159                         return false;
160                 }
161
162                 return true;
163         }
164 };
165
166 class PasswordHistory : public DomainPolicy<DataSetInt> {
167 public:
168         PasswordHistory() : DomainPolicy("password-history")
169         {
170         }
171
172         bool apply(const DataType& value, uid_t domain)
173         {
174                 try {
175                         PasswordManager passwordManager(domain);
176                         passwordManager.setHistory(inverse(value));
177                         passwordManager.enforce();
178                 } catch (runtime::Exception &e) {
179                         ERROR(e.what());
180                         return false;
181                 }
182
183                 return true;
184         }
185 };
186
187 class PasswordExpire : public DomainPolicy<DataSetInt> {
188 public:
189         PasswordExpire() : DomainPolicy("password-expired")
190         {
191         }
192
193         bool apply(const DataType& value, uid_t domain)
194         {
195                 try {
196                         PasswordManager passwordManager(domain);
197                         passwordManager.setExpires(value);
198                         passwordManager.enforce();
199                 } catch (runtime::Exception &e) {
200                         ERROR(e.what());
201                         return false;
202                 }
203
204                 return true;
205         }
206 };
207
208 class PasswordFailureCount : public DomainPolicy<DataSetInt> {
209 public:
210         PasswordFailureCount() : DomainPolicy("password-maximum-failure-count")
211         {
212         }
213
214         bool apply(const DataType& value, uid_t domain)
215         {
216                 try {
217                         PasswordManager passwordManager(domain);
218                         passwordManager.setMaximumFailedForWipe(value);
219                         passwordManager.enforce();
220                 } catch (runtime::Exception &e) {
221                         ERROR(e.what());
222                         return false;
223                 }
224
225                 return true;
226         }
227 };
228
229 class PasswordComplexity : public DomainPolicy<DataSetInt> {
230 public:
231         PasswordComplexity() : DomainPolicy("password-minimum-complexity")
232         {
233         }
234
235         bool apply(const DataType& value, uid_t domain)
236         {
237                 try {
238                         PasswordManager passwordManager(domain);
239                         passwordManager.setMinimumComplexCharacters(inverse(value));
240                         passwordManager.enforce();
241                 } catch (runtime::Exception &e) {
242                         ERROR(e.what());
243                         return false;
244                 }
245
246                 return true;
247         }
248 };
249
250 class PasswordLength : public DomainPolicy<DataSetInt> {
251 public:
252         PasswordLength() : DomainPolicy("password-minimum-length")
253         {
254         }
255
256         bool apply(const DataType& value, uid_t domain)
257         {
258                 try {
259                         PasswordManager passwordManager(domain);
260                         passwordManager.setMinimumLength(inverse(value));
261                         passwordManager.enforce();
262                 } catch (runtime::Exception &e) {
263                         ERROR(e.what());
264                         return false;
265                 }
266
267                 return true;
268         }
269 };
270
271 class PasswordTimeout : public DomainPolicy<DataSetInt> {
272 public:
273         PasswordTimeout() : DomainPolicy("password-inactivity-timeout")
274         {
275         }
276
277         bool apply(const DataType& value, uid_t domain)
278         {
279                 return true;
280         }
281 };
282
283 class PasswordRecovery : public DomainPolicy<DataSetInt> {
284 public:
285         PasswordRecovery() : DomainPolicy("password-recovery")
286         {
287         }
288
289         bool apply(const DataType& value, uid_t domain)
290         {
291                 return true;
292         }
293 };
294
295 class Password : public AbstractPolicyProvider {
296 public:
297         int setQuality(int quality);
298         int getQuality();
299         int setMinimumLength(int value);
300         int getMinimumLength();
301         int setMinComplexChars(int value);
302         int getMinComplexChars();
303         int setMaximumFailedForWipe(int value);
304         int getMaximumFailedForWipe();
305         int setExpires(int value);
306         int getExpires();
307         int setHistory(int value);
308         int getHistory();
309         int setPattern(const std::string &pattern);
310         int reset(const std::string &passwd);
311         int enforceChange();
312         int setMaxInactivityTimeDeviceLock(int value);
313         int getMaxInactivityTimeDeviceLock();
314         int setStatus(int status);
315         int getStatus();
316         int deletePattern();
317         std::string getPattern();
318         int setMaximumCharacterOccurrences(int value);
319         int getMaximumCharacterOccurrences();
320         int setMaximumNumericSequenceLength(int value);
321         int getMaximumNumericSequenceLength();
322         int setForbiddenStrings(const std::vector<std::string> &forbiddenStrings);
323         std::vector<std::string> getForbiddenStrings();
324         int setRecovery(int enable);
325         int getRecovery();
326
327 private:
328         PasswordQuality      quality;
329         PasswordHistory      history;
330         PasswordLength       length;
331         PasswordComplexity   complexity;
332         PasswordTimeout      timeout;
333         PasswordExpire       expire;
334         PasswordFailureCount failureCount;
335         PasswordSequences    sequences;
336         PasswordOccurrences  occurrences;
337         PasswordRecovery     recovery;
338 };
339
340 int Password::setQuality(int value)
341 {
342         try {
343                 quality.set(inverse(value));
344                 if (value & DPM_PASSWORD_QUALITY_SIMPLE_PASSWORD) {
345                         length.set(inverse(simplePasswordLength));
346                 }
347         } catch (runtime::Exception& e) {
348                 ERROR(e.what());
349                 return -1;
350         }
351
352         return 0;
353 }
354
355 int Password::getQuality()
356 {
357         int value = quality.get();
358         return inverse(value);
359 }
360
361 int Password::setMinimumLength(int value)
362 {
363         try {
364                 value = inverse(value);
365                 length.set(value);
366         } catch (runtime::Exception& e) {
367                 ERROR(e.what());
368                 return -1;
369         }
370
371         return 0;
372 }
373
374 int Password::getMinimumLength()
375 {
376         int value = length.get();
377         return inverse(value);
378 }
379
380 int Password::setMinComplexChars(int value)
381 {
382         try {
383                 value = inverse(value);
384                 complexity.set(value);
385         } catch (runtime::Exception& e) {
386                 ERROR(e.what());
387                 return -1;
388         }
389
390         return 0;
391 }
392
393 int Password::getMinComplexChars()
394 {
395         int value = complexity.get();
396         return inverse(value);
397 }
398
399 int Password::setMaximumFailedForWipe(int value)
400 {
401         try {
402                 value = value == 0 ? infinite : value;
403                 failureCount.set(value);
404         } catch (runtime::Exception& e) {
405                 ERROR(e.what());
406                 return -1;
407         }
408
409         return 0;
410 }
411
412 int Password::getMaximumFailedForWipe()
413 {
414         int value = failureCount.get();
415         return value == infinite ? 0 : value;
416 }
417
418 int Password::setExpires(int value)
419 {
420         try {
421                 value = value == 0 ? infinite : value;
422                 expire.set(value);
423         } catch (runtime::Exception& e) {
424                 ERROR(e.what());
425                 return -1;
426         }
427
428         return 0;
429 }
430
431 int Password::getExpires()
432 {
433         int value = expire.get();
434         return value == infinite ? 0 : value;
435 }
436
437 int Password::setHistory(int value)
438 {
439         try {
440                 value = inverse(value);
441                 history.set(value);
442         } catch (runtime::Exception& e) {
443                 ERROR(e.what());
444                 return -1;
445         }
446
447         return 0;
448 }
449
450 int Password::getHistory()
451 {
452         int value = history.get();
453         return inverse(value);
454 }
455
456 int Password::reset(const std::string &passwd)
457 {
458         try {
459                 PasswordManager passwordManager(rmi::Service::getPeerUid());
460                 passwordManager.resetPassword(passwd);
461         } catch (runtime::Exception& e) {
462                 ERROR(e.what());
463                 return -1;
464         }
465
466         return 0;
467 }
468
469 int Password::enforceChange()
470 {
471         try {
472                 Bundle bundle;
473                 bundle.add("id", "password-enforce-change");
474
475                 Launchpad launchpad(rmi::Service::getPeerUid());
476                 launchpad.launch("org.tizen.dpm-syspopup", bundle);
477                 passwordStatus[rmi::Service::getPeerUid()] = DPM_PASSWORD_STATUS_CHANGE_REQUIRED;
478         } catch (runtime::Exception& e) {
479                 ERROR(e.what());
480                 return -1;
481         }
482
483         return 0;
484 }
485
486 int Password::setMaxInactivityTimeDeviceLock(int value)
487 {
488         try {
489                 value = value == 0 ? infinite : value;
490                 timeout.set(value);
491         } catch (runtime::Exception& e) {
492                 ERROR(e.what());
493                 return -1;
494         }
495
496         return 0;
497 }
498
499 int Password::getMaxInactivityTimeDeviceLock()
500 {
501         int value = timeout.get();
502         return value == infinite ? 0 : value;
503 }
504
505 int Password::setStatus(int status)
506 {
507         if (status >= DPM_PASSWORD_STATUS_MAX) {
508                 ERROR("Invalid password status");
509                 return -1;
510         }
511
512         passwordStatus[rmi::Service::getPeerUid()] = status;
513         //ctx.notify("password", "password-status");
514
515         return 0;
516 }
517
518 int Password::getStatus()
519 {
520         return passwordStatus[rmi::Service::getPeerUid()];
521 }
522
523 int Password::setMaximumCharacterOccurrences(int value)
524 {
525         try {
526                 value = value == 0 ? infinite : value;
527                 occurrences.set(value);
528         } catch (runtime::Exception& e) {
529                 ERROR(e.what());
530                 return -1;
531         }
532
533         return 0;
534 }
535
536 int Password::getMaximumCharacterOccurrences()
537 {
538         int value = occurrences.get();
539         return value == infinite ? 0 : value;
540 }
541
542 int Password::setMaximumNumericSequenceLength(int value)
543 {
544         try {
545                 value = value == 0 ? infinite : value;
546                 sequences.set(value);
547         } catch (runtime::Exception& e) {
548                 ERROR(e.what());
549                 return -1;
550         }
551
552         return 0;
553 }
554
555 int Password::getMaximumNumericSequenceLength()
556 {
557         int value = sequences.get();
558         return value == infinite ? 0 : value;
559 }
560
561 int Password::setRecovery(int enable)
562 {
563         try {
564                 enable = inverse(enable);
565                 recovery.set(enable);
566         } catch (runtime::Exception& e) {
567                 ERROR(e.what());
568                 return -1;
569         }
570
571         return 0;
572 }
573
574 int Password::getRecovery()
575 {
576         int value = recovery.get();
577         return inverse(value);
578 }
579
580 extern "C" {
581
582 #define PRIVILEGE "http://tizen.org/privilege/dpm.password"
583
584 AbstractPolicyProvider *PolicyFactory(PolicyControlContext& context)
585 {
586         Password *policy = new Password();
587
588         context.expose(policy, PRIVILEGE, (int)(Password::setQuality)(int));
589         context.expose(policy, PRIVILEGE, (int)(Password::setMinimumLength)(int));
590         context.expose(policy, PRIVILEGE, (int)(Password::setMinComplexChars)(int));
591         context.expose(policy, PRIVILEGE, (int)(Password::setMaximumFailedForWipe)(int));
592         context.expose(policy, PRIVILEGE, (int)(Password::setExpires)(int));
593         context.expose(policy, PRIVILEGE, (int)(Password::setHistory)(int));
594         context.expose(policy, PRIVILEGE, (int)(Password::reset)(std::string));
595         context.expose(policy, PRIVILEGE, (int)(Password::enforceChange)());
596         context.expose(policy, PRIVILEGE, (int)(Password::setMaxInactivityTimeDeviceLock)(int));
597         context.expose(policy, PRIVILEGE, (int)(Password::setStatus)(int));
598         context.expose(policy, PRIVILEGE, (int)(Password::setMaximumCharacterOccurrences)(int));
599         context.expose(policy, PRIVILEGE, (int)(Password::setMaximumNumericSequenceLength)(int));
600         context.expose(policy, PRIVILEGE, (int)(Password::setRecovery)(int));
601
602         context.expose(policy, "", (int)(Password::getStatus)());
603         context.expose(policy, PRIVILEGE, (int)(Password::getQuality)());
604         context.expose(policy, PRIVILEGE, (int)(Password::getMinimumLength)());
605         context.expose(policy, PRIVILEGE, (int)(Password::getMinComplexChars)());
606         context.expose(policy, PRIVILEGE, (int)(Password::getMaximumFailedForWipe)());
607         context.expose(policy, PRIVILEGE, (int)(Password::getExpires)());
608         context.expose(policy, PRIVILEGE, (int)(Password::getHistory)());
609         context.expose(policy, PRIVILEGE, (int)(Password::getMaxInactivityTimeDeviceLock)());
610         context.expose(policy, PRIVILEGE, (int)(Password::getMaximumCharacterOccurrences)());
611         context.expose(policy, PRIVILEGE, (int)(Password::getMaximumNumericSequenceLength)());
612         context.expose(policy, "", (int)(Password::getRecovery)());
613
614         return policy;
615 }
616
617 } // extern "C"