2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
7 #include "AuthenticationManager.h"
12 #include <sys/param.h>
20 #include <StringList.h>
22 #include <AutoDeleter.h>
23 #include <LaunchRoster.h>
24 #include <RegistrarDefs.h>
26 #include <libroot_private.h>
27 #include <user_group.h>
28 #include <util/KMessage.h>
34 using namespace BPrivate
;
37 typedef std::set
<std::string
> StringSet
;
40 class AuthenticationManager::FlatStore
{
45 fBuffer
.SetBlockSize(1024);
48 void WriteData(size_t offset
, const void* data
, size_t length
)
50 ssize_t result
= fBuffer
.WriteAt(offset
, data
, length
);
52 throw status_t(result
);
55 template<typename Type
>
56 void WriteData(size_t offset
, const Type
& data
)
58 WriteData(&data
, sizeof(Type
));
61 size_t ReserveSpace(size_t length
, bool align
)
64 fSize
= _ALIGN(fSize
);
72 void* AppendData(const void* data
, size_t length
, bool align
)
74 size_t pos
= ReserveSpace(length
, align
);
75 WriteData(pos
, data
, length
);
76 return (void*)(addr_t
)pos
;
79 template<typename Type
>
80 Type
* AppendData(const Type
& data
)
82 return (Type
*)AppendData(&data
, sizeof(Type
), true);
85 char* AppendString(const char* string
)
87 return (char*)AppendData(string
, strlen(string
) + 1, false);
90 char* AppendString(const string
& str
)
92 return (char*)AppendData(str
.c_str(), str
.length() + 1, false);
95 const void* Buffer() const
97 return fBuffer
.Buffer();
100 size_t BufferLength() const
111 class AuthenticationManager::User
{
127 User(const char* name
, const char* password
, uid_t uid
, gid_t gid
,
128 const char* home
, const char* shell
, const char* realName
)
147 User(const User
& other
)
152 fPassword(other
.fPassword
),
154 fShell(other
.fShell
),
155 fRealName(other
.fRealName
),
156 fShadowPassword(other
.fShadowPassword
),
157 fLastChanged(other
.fLastChanged
),
161 fInactive(other
.fInactive
),
162 fExpiration(other
.fExpiration
),
167 const string
& Name() const { return fName
; }
168 const uid_t
UID() const { return fUID
; }
170 void SetShadowInfo(const char* password
, int lastChanged
, int min
, int max
,
171 int warn
, int inactive
, int expiration
, int flags
)
173 fShadowPassword
= password
;
174 fLastChanged
= lastChanged
;
178 fInactive
= inactive
;
179 fExpiration
= expiration
;
183 void UpdateFromMessage(const KMessage
& message
)
186 const char* stringValue
;
188 if (message
.FindInt32("uid", &intValue
) == B_OK
)
191 if (message
.FindInt32("gid", &intValue
) == B_OK
)
194 if (message
.FindString("name", &stringValue
) == B_OK
)
197 if (message
.FindString("password", &stringValue
) == B_OK
)
198 fPassword
= stringValue
;
200 if (message
.FindString("home", &stringValue
) == B_OK
)
203 if (message
.FindString("shell", &stringValue
) == B_OK
)
204 fShell
= stringValue
;
206 if (message
.FindString("real name", &stringValue
) == B_OK
)
207 fRealName
= stringValue
;
209 if (message
.FindString("shadow password", &stringValue
) == B_OK
) {
210 fShadowPassword
= stringValue
;
212 // fLastChanged = now;
215 if (message
.FindInt32("last changed", &intValue
) == B_OK
)
216 fLastChanged
= intValue
;
218 if (message
.FindInt32("min", &intValue
) == B_OK
)
221 if (message
.FindInt32("max", &intValue
) == B_OK
)
224 if (message
.FindInt32("warn", &intValue
) == B_OK
)
227 if (message
.FindInt32("inactive", &intValue
) == B_OK
)
228 fInactive
= intValue
;
230 if (message
.FindInt32("expiration", &intValue
) == B_OK
)
231 fExpiration
= intValue
;
233 if (message
.FindInt32("flags", &intValue
) == B_OK
)
237 passwd
* WriteFlatPasswd(FlatStore
& store
) const
239 struct passwd passwd
;
241 passwd
.pw_uid
= fUID
;
242 passwd
.pw_gid
= fGID
;
243 passwd
.pw_name
= store
.AppendString(fName
);
244 passwd
.pw_passwd
= store
.AppendString(fPassword
);
245 passwd
.pw_dir
= store
.AppendString(fHome
);
246 passwd
.pw_shell
= store
.AppendString(fShell
);
247 passwd
.pw_gecos
= store
.AppendString(fRealName
);
249 return store
.AppendData(passwd
);
252 spwd
* WriteFlatShadowPwd(FlatStore
& store
) const
256 spwd
.sp_namp
= store
.AppendString(fName
);
257 spwd
.sp_pwdp
= store
.AppendString(fShadowPassword
);
258 spwd
.sp_lstchg
= fLastChanged
;
261 spwd
.sp_warn
= fWarn
;
262 spwd
.sp_inact
= fInactive
;
263 spwd
.sp_expire
= fExpiration
;
264 spwd
.sp_flag
= fFlags
;
266 return store
.AppendData(spwd
);
269 status_t
WriteToMessage(KMessage
& message
, bool addShadowPwd
)
272 if ((error
= message
.AddInt32("uid", fUID
)) != B_OK
273 || (error
= message
.AddInt32("gid", fGID
)) != B_OK
274 || (error
= message
.AddString("name", fName
.c_str())) != B_OK
275 || (error
= message
.AddString("password", fPassword
.c_str()))
277 || (error
= message
.AddString("home", fHome
.c_str())) != B_OK
278 || (error
= message
.AddString("shell", fShell
.c_str())) != B_OK
279 || (error
= message
.AddString("real name", fRealName
.c_str()))
287 if ((error
= message
.AddString("shadow password",
288 fShadowPassword
.c_str())) != B_OK
289 || (error
= message
.AddInt32("last changed", fLastChanged
)) != B_OK
290 || (error
= message
.AddInt32("min", fMin
)) != B_OK
291 || (error
= message
.AddInt32("max", fMax
)) != B_OK
292 || (error
= message
.AddInt32("warn", fWarn
)) != B_OK
293 || (error
= message
.AddInt32("inactive", fInactive
)) != B_OK
294 || (error
= message
.AddInt32("expiration", fExpiration
)) != B_OK
295 || (error
= message
.AddInt32("flags", fFlags
)) != B_OK
) {
302 void WritePasswdLine(FILE* file
)
304 fprintf(file
, "%s:%s:%d:%d:%s:%s:%s\n",
305 fName
.c_str(), fPassword
.c_str(), (int)fUID
, (int)fGID
,
306 fRealName
.c_str(), fHome
.c_str(), fShell
.c_str());
309 void WriteShadowPwdLine(FILE* file
)
311 fprintf(file
, "%s:%s:%d:", fName
.c_str(), fShadowPassword
.c_str(),
314 // The following values are supposed to be printed as empty strings,
316 int values
[5] = { fMin
, fMax
, fWarn
, fInactive
, fExpiration
};
317 for (int i
= 0; i
< 5; i
++) {
319 fprintf(file
, "%d", values
[i
]);
323 fprintf(file
, "%d\n", fFlags
);
334 string fShadowPassword
;
345 class AuthenticationManager::Group
{
356 Group(const char* name
, const char* password
, gid_t gid
,
357 const char* const* members
, int memberCount
)
364 for (int i
= 0; i
< memberCount
; i
++)
365 fMembers
.insert(members
[i
]);
372 const string
& Name() const { return fName
; }
373 const gid_t
GID() const { return fGID
; }
375 bool HasMember(const char* name
)
378 return fMembers
.find(name
) != fMembers
.end();
384 bool MemberRemoved(const std::string
& name
)
386 return fMembers
.erase(name
) > 0;
389 void UpdateFromMessage(const KMessage
& message
)
392 if (message
.FindInt32("gid", &intValue
) == B_OK
)
395 const char* stringValue
;
396 if (message
.FindString("name", &stringValue
) == B_OK
)
399 if (message
.FindString("password", &stringValue
) == B_OK
)
400 fPassword
= stringValue
;
402 if (message
.FindString("members", &stringValue
) == B_OK
) {
405 (stringValue
= message
.GetString("members", i
, NULL
)) != NULL
;
407 if (stringValue
!= NULL
&& *stringValue
!= '\0')
408 fMembers
.insert(stringValue
);
413 group
* WriteFlatGroup(FlatStore
& store
) const
417 char* members
[MAX_GROUP_MEMBER_COUNT
+ 1];
419 for (StringSet::const_iterator it
= fMembers
.begin();
420 it
!= fMembers
.end(); ++it
) {
421 members
[count
++] = store
.AppendString(it
->c_str());
423 members
[count
] = (char*)-1;
426 group
.gr_name
= store
.AppendString(fName
);
427 group
.gr_passwd
= store
.AppendString(fPassword
);
428 group
.gr_mem
= (char**)store
.AppendData(members
,
429 sizeof(char*) * (count
+ 1), true);
431 return store
.AppendData(group
);
434 status_t
WriteToMessage(KMessage
& message
)
437 if ((error
= message
.AddInt32("gid", fGID
)) != B_OK
438 || (error
= message
.AddString("name", fName
.c_str())) != B_OK
439 || (error
= message
.AddString("password", fPassword
.c_str()))
444 for (StringSet::const_iterator it
= fMembers
.begin();
445 it
!= fMembers
.end(); ++it
) {
446 if ((error
= message
.AddString("members", it
->c_str())) != B_OK
)
453 void WriteGroupLine(FILE* file
)
455 fprintf(file
, "%s:%s:%d:",
456 fName
.c_str(), fPassword
.c_str(), (int)fGID
);
457 for (StringSet::const_iterator it
= fMembers
.begin();
458 it
!= fMembers
.end(); ++it
) {
459 if (it
== fMembers
.begin())
460 fprintf(file
, "%s", it
->c_str());
462 fprintf(file
, ",%s", it
->c_str());
475 class AuthenticationManager::UserDB
{
477 status_t
AddUser(User
* user
)
480 fUsersByID
[user
->UID()] = user
;
486 fUsersByName
[user
->Name()] = user
;
488 fUsersByID
.erase(fUsersByID
.find(user
->UID()));
495 void RemoveUser(User
* user
)
497 fUsersByID
.erase(fUsersByID
.find(user
->UID()));
498 fUsersByName
.erase(fUsersByName
.find(user
->Name()));
501 User
* UserByID(uid_t uid
) const
503 map
<uid_t
, User
*>::const_iterator it
= fUsersByID
.find(uid
);
504 return (it
== fUsersByID
.end() ? NULL
: it
->second
);
507 User
* UserByName(const char* name
) const
509 map
<string
, User
*>::const_iterator it
= fUsersByName
.find(name
);
510 return (it
== fUsersByName
.end() ? NULL
: it
->second
);
513 int32
WriteFlatPasswdDB(FlatStore
& store
) const
515 int32 count
= fUsersByID
.size();
517 size_t entriesSpace
= sizeof(passwd
*) * count
;
518 size_t offset
= store
.ReserveSpace(entriesSpace
, true);
519 passwd
** entries
= new passwd
*[count
];
520 ArrayDeleter
<passwd
*> _(entries
);
523 for (map
<uid_t
, User
*>::const_iterator it
= fUsersByID
.begin();
524 it
!= fUsersByID
.end(); ++it
) {
525 entries
[index
++] = it
->second
->WriteFlatPasswd(store
);
528 store
.WriteData(offset
, entries
, entriesSpace
);
533 int32
WriteFlatShadowDB(FlatStore
& store
) const
535 int32 count
= fUsersByID
.size();
537 size_t entriesSpace
= sizeof(spwd
*) * count
;
538 size_t offset
= store
.ReserveSpace(entriesSpace
, true);
539 spwd
** entries
= new spwd
*[count
];
540 ArrayDeleter
<spwd
*> _(entries
);
543 for (map
<uid_t
, User
*>::const_iterator it
= fUsersByID
.begin();
544 it
!= fUsersByID
.end(); ++it
) {
545 entries
[index
++] = it
->second
->WriteFlatShadowPwd(store
);
548 store
.WriteData(offset
, entries
, entriesSpace
);
555 // rename the old files
556 string
passwdBackup(kPasswdFile
);
557 string
shadowBackup(kShadowPwdFile
);
558 passwdBackup
+= ".old";
559 shadowBackup
+= ".old";
561 rename(kPasswdFile
, passwdBackup
.c_str());
562 rename(kShadowPwdFile
, shadowBackup
.c_str());
563 // Don't check errors. We can't do anything anyway.
566 FILE* passwdFile
= fopen(kPasswdFile
, "w");
567 if (passwdFile
== NULL
) {
568 debug_printf("REG: Failed to open passwd file \"%s\" for "
569 "writing: %s\n", kPasswdFile
, strerror(errno
));
571 CObjectDeleter
<FILE, int> _1(passwdFile
, fclose
);
573 FILE* shadowFile
= fopen(kShadowPwdFile
, "w");
574 if (shadowFile
== NULL
) {
575 debug_printf("REG: Failed to open shadow passwd file \"%s\" for "
576 "writing: %s\n", kShadowPwdFile
, strerror(errno
));
578 CObjectDeleter
<FILE, int> _2(shadowFile
, fclose
);
581 for (map
<uid_t
, User
*>::const_iterator it
= fUsersByID
.begin();
582 it
!= fUsersByID
.end(); ++it
) {
583 User
* user
= it
->second
;
584 user
->WritePasswdLine(passwdFile
);
585 user
->WriteShadowPwdLine(shadowFile
);
590 map
<uid_t
, User
*> fUsersByID
;
591 map
<string
, User
*> fUsersByName
;
595 class AuthenticationManager::GroupDB
{
597 status_t
AddGroup(Group
* group
)
600 fGroupsByID
[group
->GID()] = group
;
606 fGroupsByName
[group
->Name()] = group
;
608 fGroupsByID
.erase(fGroupsByID
.find(group
->GID()));
615 void RemoveGroup(Group
* group
)
617 fGroupsByID
.erase(fGroupsByID
.find(group
->GID()));
618 fGroupsByName
.erase(fGroupsByName
.find(group
->Name()));
621 bool UserRemoved(const std::string
& user
)
623 bool changed
= false;
624 for (map
<gid_t
, Group
*>::const_iterator it
= fGroupsByID
.begin();
625 it
!= fGroupsByID
.end(); ++it
) {
626 Group
* group
= it
->second
;
627 changed
|= group
->MemberRemoved(user
);
632 Group
* GroupByID(gid_t gid
) const
634 map
<gid_t
, Group
*>::const_iterator it
= fGroupsByID
.find(gid
);
635 return (it
== fGroupsByID
.end() ? NULL
: it
->second
);
638 Group
* GroupByName(const char* name
) const
640 map
<string
, Group
*>::const_iterator it
= fGroupsByName
.find(name
);
641 return (it
== fGroupsByName
.end() ? NULL
: it
->second
);
644 int32
GetUserGroups(const char* name
, gid_t
* groups
, int maxCount
)
648 for (map
<gid_t
, Group
*>::const_iterator it
= fGroupsByID
.begin();
649 it
!= fGroupsByID
.end(); ++it
) {
650 Group
* group
= it
->second
;
651 if (group
->HasMember(name
)) {
652 if (count
< maxCount
)
653 groups
[count
] = group
->GID();
662 int32
WriteFlatGroupDB(FlatStore
& store
) const
664 int32 count
= fGroupsByID
.size();
666 size_t entriesSpace
= sizeof(group
*) * count
;
667 size_t offset
= store
.ReserveSpace(entriesSpace
, true);
668 group
** entries
= new group
*[count
];
669 ArrayDeleter
<group
*> _(entries
);
672 for (map
<gid_t
, Group
*>::const_iterator it
= fGroupsByID
.begin();
673 it
!= fGroupsByID
.end(); ++it
) {
674 entries
[index
++] = it
->second
->WriteFlatGroup(store
);
677 store
.WriteData(offset
, entries
, entriesSpace
);
684 // rename the old files
685 string
groupBackup(kGroupFile
);
686 groupBackup
+= ".old";
688 rename(kGroupFile
, groupBackup
.c_str());
689 // Don't check errors. We can't do anything anyway.
692 FILE* groupFile
= fopen(kGroupFile
, "w");
693 if (groupFile
== NULL
) {
694 debug_printf("REG: Failed to open group file \"%s\" for "
695 "writing: %s\n", kGroupFile
, strerror(errno
));
697 CObjectDeleter
<FILE, int> _1(groupFile
, fclose
);
700 for (map
<gid_t
, Group
*>::const_iterator it
= fGroupsByID
.begin();
701 it
!= fGroupsByID
.end(); ++it
) {
702 Group
* group
= it
->second
;
703 group
->WriteGroupLine(groupFile
);
708 map
<uid_t
, Group
*> fGroupsByID
;
709 map
<string
, Group
*> fGroupsByName
;
713 AuthenticationManager::AuthenticationManager()
719 fPasswdDBReply(NULL
),
721 fShadowPwdDBReply(NULL
)
726 AuthenticationManager::~AuthenticationManager()
728 // Quit the request thread and wait for it to finish
729 write_port(fRequestPort
, 'quit', NULL
, 0);
730 wait_for_thread(fRequestThread
, NULL
);
734 delete fPasswdDBReply
;
735 delete fGroupDBReply
;
736 delete fShadowPwdDBReply
;
741 AuthenticationManager::Init()
743 fUserDB
= new(std::nothrow
) UserDB
;
744 fGroupDB
= new(std::nothrow
) GroupDB
;
745 fPasswdDBReply
= new(std::nothrow
) KMessage(1);
746 fGroupDBReply
= new(std::nothrow
) KMessage(1);
747 fShadowPwdDBReply
= new(std::nothrow
) KMessage(1);
749 if (fUserDB
== NULL
|| fGroupDB
== NULL
|| fPasswdDBReply
== NULL
750 || fGroupDBReply
== NULL
|| fShadowPwdDBReply
== NULL
) {
754 fRequestPort
= BLaunchRoster().GetPort(
755 B_REGISTRAR_AUTHENTICATION_PORT_NAME
);
756 if (fRequestPort
< 0)
759 fRequestThread
= spawn_thread(&_RequestThreadEntry
,
760 "authentication manager", B_NORMAL_PRIORITY
+ 1, this);
761 if (fRequestThread
< 0)
762 return fRequestThread
;
764 resume_thread(fRequestThread
);
771 AuthenticationManager::_RequestThreadEntry(void* data
)
773 return ((AuthenticationManager
*)data
)->_RequestThread();
778 AuthenticationManager::_RequestThread()
786 team_id registrarTeam
= -1;
789 if (get_thread_info(find_thread(NULL
), &info
) == B_OK
)
790 registrarTeam
= info
.team
;
796 port_message_info messageInfo
;
797 status_t error
= message
.ReceiveFrom(fRequestPort
, -1, &messageInfo
);
801 bool isRoot
= (messageInfo
.sender
== 0);
803 switch (message
.What()) {
804 case B_REG_GET_PASSWD_DB
:
806 // lazily build the reply
808 if (fPasswdDBReply
->What() == 1) {
810 int32 count
= fUserDB
->WriteFlatPasswdDB(store
);
811 if (fPasswdDBReply
->AddInt32("count", count
) != B_OK
812 || fPasswdDBReply
->AddData("entries", B_RAW_TYPE
,
813 store
.Buffer(), store
.BufferLength(),
818 fPasswdDBReply
->SetWhat(0);
825 message
.SendReply(fPasswdDBReply
, -1, -1, 0, registrarTeam
);
827 _InvalidatePasswdDBReply();
828 KMessage
reply(error
);
829 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
835 case B_REG_GET_GROUP_DB
:
837 // lazily build the reply
839 if (fGroupDBReply
->What() == 1) {
841 int32 count
= fGroupDB
->WriteFlatGroupDB(store
);
842 if (fGroupDBReply
->AddInt32("count", count
) != B_OK
843 || fGroupDBReply
->AddData("entries", B_RAW_TYPE
,
844 store
.Buffer(), store
.BufferLength(),
849 fGroupDBReply
->SetWhat(0);
856 message
.SendReply(fGroupDBReply
, -1, -1, 0, registrarTeam
);
858 _InvalidateGroupDBReply();
859 KMessage
reply(error
);
860 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
867 case B_REG_GET_SHADOW_PASSWD_DB
:
869 // only root may see the shadow passwd
873 // lazily build the reply
875 if (error
== B_OK
&& fShadowPwdDBReply
->What() == 1) {
877 int32 count
= fUserDB
->WriteFlatShadowDB(store
);
878 if (fShadowPwdDBReply
->AddInt32("count", count
) != B_OK
879 || fShadowPwdDBReply
->AddData("entries", B_RAW_TYPE
,
880 store
.Buffer(), store
.BufferLength(),
885 fShadowPwdDBReply
->SetWhat(0);
892 message
.SendReply(fShadowPwdDBReply
, -1, -1, 0,
895 _InvalidateShadowPwdDBReply();
896 KMessage
reply(error
);
897 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
910 if (message
.FindInt32("uid", &uid
) == B_OK
) {
911 user
= fUserDB
->UserByID(uid
);
912 } else if (message
.FindString("name", &name
) == B_OK
) {
913 user
= fUserDB
->UserByName(name
);
918 if (error
== B_OK
&& user
== NULL
)
921 bool getShadowPwd
= message
.GetBool("shadow", false);
923 // only root may see the shadow passwd
924 if (error
== B_OK
&& getShadowPwd
&& !isRoot
)
927 // add user to message
930 error
= user
->WriteToMessage(reply
, getShadowPwd
);
933 reply
.SetWhat(error
);
934 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
939 case B_REG_GET_GROUP
:
946 if (message
.FindInt32("gid", &gid
) == B_OK
) {
947 group
= fGroupDB
->GroupByID(gid
);
948 } else if (message
.FindString("name", &name
) == B_OK
) {
949 group
= fGroupDB
->GroupByName(name
);
954 if (error
== B_OK
&& group
== NULL
)
957 // add group to message
960 error
= group
->WriteToMessage(reply
);
963 reply
.SetWhat(error
);
964 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
969 case B_REG_GET_USER_GROUPS
:
974 if (message
.FindString("name", &name
) != B_OK
975 || message
.FindInt32("max count", &maxCount
) != B_OK
981 gid_t groups
[NGROUPS_MAX
+ 1];
984 maxCount
= min_c(maxCount
, NGROUPS_MAX
+ 1);
985 count
= fGroupDB
->GetUserGroups(name
, groups
, maxCount
);
988 // add groups to message
991 if (reply
.AddInt32("count", count
) != B_OK
992 || reply
.AddData("groups", B_INT32_TYPE
,
993 groups
, min_c(maxCount
, count
) * sizeof(gid_t
),
1000 reply
.SetWhat(error
);
1001 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
1006 case B_REG_UPDATE_USER
:
1013 if (message
.FindInt32("uid", &uid
) == B_OK
) {
1014 user
= fUserDB
->UserByID(uid
);
1015 } else if (message
.FindString("name", &name
) == B_OK
) {
1016 user
= fUserDB
->UserByName(name
);
1018 error
= B_BAD_VALUE
;
1021 // only root can change anything
1022 if (error
== B_OK
&& !isRoot
)
1025 // check addUser vs. existing user
1026 bool addUser
= message
.GetBool("add user", false);
1027 if (error
== B_OK
) {
1031 } else if (user
== NULL
)
1035 // apply all changes
1036 if (error
== B_OK
) {
1037 // clone the user object and update it from the message
1038 User
* oldUser
= user
;
1041 user
= (oldUser
!= NULL
? new User(*oldUser
)
1043 user
->UpdateFromMessage(message
);
1045 // uid and name should remain the same
1046 if (oldUser
!= NULL
) {
1047 if (oldUser
->UID() != user
->UID()
1048 || oldUser
->Name() != user
->Name()) {
1049 error
= B_BAD_VALUE
;
1053 // replace the old user and write DBs to disk
1054 if (error
== B_OK
) {
1055 fUserDB
->AddUser(user
);
1056 fUserDB
->WriteToDisk();
1057 _InvalidatePasswdDBReply();
1058 _InvalidateShadowPwdDBReply();
1061 error
= B_NO_MEMORY
;
1072 reply
.SetWhat(error
);
1073 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
1078 case B_REG_DELETE_USER
:
1085 if (message
.FindInt32("uid", &uid
) == B_OK
) {
1086 user
= fUserDB
->UserByID(uid
);
1087 } else if (message
.FindString("name", &name
) == B_OK
) {
1088 user
= fUserDB
->UserByName(name
);
1090 error
= B_BAD_VALUE
;
1093 if (error
== B_OK
&& user
== NULL
)
1096 // only root can change anything
1097 if (error
== B_OK
&& !isRoot
)
1101 if (error
== B_OK
) {
1102 std::string userName
= user
->Name();
1104 fUserDB
->RemoveUser(user
);
1105 fUserDB
->WriteToDisk();
1106 _InvalidatePasswdDBReply();
1107 _InvalidateShadowPwdDBReply();
1109 if (fGroupDB
->UserRemoved(userName
)) {
1110 fGroupDB
->WriteToDisk();
1111 _InvalidateGroupDBReply();
1117 reply
.SetWhat(error
);
1118 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
1123 case B_REG_UPDATE_GROUP
:
1126 Group
* group
= NULL
;
1130 if (message
.FindInt32("gid", &gid
) == B_OK
) {
1131 group
= fGroupDB
->GroupByID(gid
);
1132 } else if (message
.FindString("name", &name
) == B_OK
) {
1133 group
= fGroupDB
->GroupByName(name
);
1135 error
= B_BAD_VALUE
;
1138 // only root can change anything
1139 if (error
== B_OK
&& !isRoot
)
1142 // check addGroup vs. existing group
1143 bool addGroup
= message
.GetBool("add group", false);
1144 if (error
== B_OK
) {
1148 } else if (group
== NULL
)
1152 // apply all changes
1153 if (error
== B_OK
) {
1154 // clone the group object and update it from the message
1155 Group
* oldGroup
= group
;
1158 group
= (oldGroup
!= NULL
? new Group(*oldGroup
)
1160 group
->UpdateFromMessage(message
);
1162 // gid and name should remain the same
1163 if (oldGroup
!= NULL
) {
1164 if (oldGroup
->GID() != group
->GID()
1165 || oldGroup
->Name() != group
->Name()) {
1166 error
= B_BAD_VALUE
;
1170 // replace the old group and write DBs to disk
1171 if (error
== B_OK
) {
1172 fGroupDB
->AddGroup(group
);
1173 fGroupDB
->WriteToDisk();
1174 _InvalidateGroupDBReply();
1177 error
= B_NO_MEMORY
;
1188 reply
.SetWhat(error
);
1189 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
1194 case B_REG_DELETE_GROUP
:
1197 Group
* group
= NULL
;
1201 if (message
.FindInt32("gid", &gid
) == B_OK
) {
1202 group
= fGroupDB
->GroupByID(gid
);
1203 } else if (message
.FindString("name", &name
) == B_OK
) {
1204 group
= fGroupDB
->GroupByName(name
);
1206 error
= B_BAD_VALUE
;
1209 if (error
== B_OK
&& group
== NULL
)
1212 // only root can change anything
1213 if (error
== B_OK
&& !isRoot
)
1217 if (error
== B_OK
) {
1218 fGroupDB
->RemoveGroup(group
);
1219 fGroupDB
->WriteToDisk();
1220 _InvalidateGroupDBReply();
1225 reply
.SetWhat(error
);
1226 message
.SendReply(&reply
, -1, -1, 0, registrarTeam
);
1232 debug_printf("REG: invalid message: %" B_PRIu32
"\n",
1240 AuthenticationManager::_InitPasswdDB()
1242 FILE* file
= fopen(kPasswdFile
, "r");
1244 debug_printf("REG: Failed to open passwd DB file \"%s\": %s\n",
1245 kPasswdFile
, strerror(errno
));
1248 CObjectDeleter
<FILE, int> _(file
, fclose
);
1250 char lineBuffer
[LINE_MAX
];
1251 while (char* line
= fgets(lineBuffer
, sizeof(lineBuffer
), file
)) {
1252 if (strlen(line
) == 0)
1263 status_t error
= parse_passwd_line(line
, name
, password
, uid
, gid
,
1264 home
, shell
, realName
);
1265 if (error
!= B_OK
) {
1266 debug_printf("REG: Unparsable line in passwd DB file: \"%s\"\n",
1273 user
= new User(name
, password
, uid
, gid
, home
, shell
, realName
);
1277 if (user
== NULL
|| fUserDB
->AddUser(user
) != B_OK
) {
1279 debug_printf("REG: Out of memory\n");
1289 AuthenticationManager::_InitGroupDB()
1291 FILE* file
= fopen(kGroupFile
, "r");
1293 debug_printf("REG: Failed to open group DB file \"%s\": %s\n",
1294 kGroupFile
, strerror(errno
));
1297 CObjectDeleter
<FILE, int> _(file
, fclose
);
1299 char lineBuffer
[LINE_MAX
];
1300 while (char* line
= fgets(lineBuffer
, sizeof(lineBuffer
), file
)) {
1301 if (strlen(line
) == 0)
1307 char* members
[MAX_GROUP_MEMBER_COUNT
];
1311 status_t error
= parse_group_line(line
, name
, password
, gid
, members
,
1313 if (error
!= B_OK
) {
1314 debug_printf("REG: Unparsable line in group DB file: \"%s\"\n",
1319 Group
* group
= NULL
;
1321 group
= new Group(name
, password
, gid
, members
, memberCount
);
1325 if (group
== NULL
|| fGroupDB
->AddGroup(group
) != B_OK
) {
1327 debug_printf("REG: Out of memory\n");
1337 AuthenticationManager::_InitShadowPwdDB()
1339 FILE* file
= fopen(kShadowPwdFile
, "r");
1341 debug_printf("REG: Failed to open shadow passwd DB file \"%s\": %s\n",
1342 kShadowPwdFile
, strerror(errno
));
1345 CObjectDeleter
<FILE, int> _(file
, fclose
);
1347 char lineBuffer
[LINE_MAX
];
1348 while (char* line
= fgets(lineBuffer
, sizeof(lineBuffer
), file
)) {
1349 if (strlen(line
) == 0)
1362 status_t error
= parse_shadow_pwd_line(line
, name
, password
,
1363 lastChanged
, min
, max
, warn
, inactive
, expiration
, flags
);
1364 if (error
!= B_OK
) {
1365 debug_printf("REG: Unparsable line in shadow passwd DB file: "
1366 "\"%s\"\n", strerror(errno
));
1370 User
* user
= fUserDB
->UserByName(name
);
1372 debug_printf("REG: shadow pwd entry for unknown user \"%s\"\n",
1378 user
->SetShadowInfo(password
, lastChanged
, min
, max
, warn
, inactive
,
1381 debug_printf("REG: Out of memory\n");
1391 AuthenticationManager::_InvalidatePasswdDBReply()
1393 fPasswdDBReply
->SetTo(1);
1398 AuthenticationManager::_InvalidateGroupDBReply()
1400 fGroupDBReply
->SetTo(1);
1405 AuthenticationManager::_InvalidateShadowPwdDBReply()
1407 fShadowPwdDBReply
->SetTo(1);