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