1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "AuthenticationManager.h" 7 8 #include <errno.h> 9 #include <stdlib.h> 10 #include <stdio.h> 11 #include <sys/param.h> 12 13 #include <map> 14 #include <new> 15 #include <string> 16 17 #include <DataIO.h> 18 19 #include <AutoDeleter.h> 20 #include <RegistrarDefs.h> 21 22 #include <libroot_private.h> 23 #include <user_group.h> 24 #include <util/KMessage.h> 25 26 27 using std::map; 28 using std::string; 29 30 using namespace BPrivate; 31 32 33 class AuthenticationManager::FlatStore { 34 public: 35 FlatStore() 36 : fSize(0) 37 { 38 fBuffer.SetBlockSize(1024); 39 } 40 41 void WriteData(size_t offset, const void* data, size_t length) 42 { 43 ssize_t result = fBuffer.WriteAt(offset, data, length); 44 if (result < 0) 45 throw status_t(result); 46 } 47 48 template<typename Type> 49 void WriteData(size_t offset, const Type& data) 50 { 51 WriteData(&data, sizeof(Type)); 52 } 53 54 size_t ReserveSpace(size_t length, bool align) 55 { 56 if (align) 57 fSize = _ALIGN(fSize); 58 59 size_t pos = fSize; 60 fSize += length; 61 62 return pos; 63 } 64 65 void* AppendData(const void* data, size_t length, bool align) 66 { 67 size_t pos = ReserveSpace(length, align); 68 WriteData(pos, data, length); 69 return (void*)(addr_t)pos; 70 } 71 72 template<typename Type> 73 Type* AppendData(const Type& data) 74 { 75 return (Type*)AppendData(&data, sizeof(Type), true); 76 } 77 78 char* AppendString(const char* string) 79 { 80 return (char*)AppendData(string, strlen(string) + 1, false); 81 } 82 83 char* AppendString(const string& str) 84 { 85 return (char*)AppendData(str.c_str(), str.length() + 1, false); 86 } 87 88 const void* Buffer() const 89 { 90 return fBuffer.Buffer(); 91 } 92 93 size_t BufferLength() const 94 { 95 return fSize; 96 } 97 98 private: 99 BMallocIO fBuffer; 100 size_t fSize; 101 }; 102 103 104 class AuthenticationManager::User { 105 public: 106 User() 107 : 108 fUID(0), 109 fGID(0), 110 fLastChanged(0), 111 fMin(-1), 112 fMax(-1), 113 fWarn(-1), 114 fInactive(-1), 115 fExpiration(-1), 116 fFlags(0) 117 { 118 } 119 120 User(const char* name, const char* password, uid_t uid, gid_t gid, 121 const char* home, const char* shell, const char* realName) 122 : 123 fUID(uid), 124 fGID(gid), 125 fName(name), 126 fPassword(password), 127 fHome(home), 128 fShell(shell), 129 fRealName(realName), 130 fLastChanged(0), 131 fMin(-1), 132 fMax(-1), 133 fWarn(-1), 134 fInactive(-1), 135 fExpiration(-1), 136 fFlags(0) 137 { 138 } 139 140 User(const User& other) 141 : 142 fUID(other.fUID), 143 fGID(other.fGID), 144 fName(other.fName), 145 fPassword(other.fPassword), 146 fHome(other.fHome), 147 fShell(other.fShell), 148 fRealName(other.fRealName), 149 fShadowPassword(other.fShadowPassword), 150 fLastChanged(other.fLastChanged), 151 fMin(other.fMin), 152 fMax(other.fMax), 153 fWarn(other.fWarn), 154 fInactive(other.fInactive), 155 fExpiration(other.fExpiration), 156 fFlags(other.fFlags) 157 { 158 } 159 160 const string& Name() const { return fName; } 161 const uid_t UID() const { return fUID; } 162 163 void SetShadowInfo(const char* password, int lastChanged, int min, int max, 164 int warn, int inactive, int expiration, int flags) 165 { 166 fShadowPassword = password; 167 fLastChanged = lastChanged; 168 fMin = min; 169 fMax = max; 170 fWarn = warn; 171 fInactive = inactive; 172 fExpiration = expiration; 173 fFlags = flags; 174 } 175 176 void UpdateFromMessage(const KMessage& message) 177 { 178 int32 intValue; 179 const char* stringValue; 180 181 if (message.FindInt32("uid", &intValue) == B_OK) 182 fUID = intValue; 183 184 if (message.FindInt32("gid", &intValue) == B_OK) 185 fGID = intValue; 186 187 if (message.FindString("name", &stringValue) == B_OK) 188 fName = stringValue; 189 190 if (message.FindString("password", &stringValue) == B_OK) 191 fPassword = stringValue; 192 193 if (message.FindString("home", &stringValue) == B_OK) 194 fHome = stringValue; 195 196 if (message.FindString("shell", &stringValue) == B_OK) 197 fShell = stringValue; 198 199 if (message.FindString("real name", &stringValue) == B_OK) 200 fRealName = stringValue; 201 202 if (message.FindString("shadow password", &stringValue) == B_OK) { 203 fShadowPassword = stringValue; 204 // TODO: 205 // fLastChanged = now; 206 } 207 208 if (message.FindInt32("min", &intValue) == B_OK) 209 fMin = intValue; 210 211 if (message.FindInt32("max", &intValue) == B_OK) 212 fMax = intValue; 213 214 if (message.FindInt32("warn", &intValue) == B_OK) 215 fWarn = intValue; 216 217 if (message.FindInt32("inactive", &intValue) == B_OK) 218 fInactive = intValue; 219 220 if (message.FindInt32("expiration", &intValue) == B_OK) 221 fExpiration = intValue; 222 223 if (message.FindInt32("flags", &intValue) == B_OK) 224 fFlags = intValue; 225 } 226 227 passwd* WriteFlatPasswd(FlatStore& store) const 228 { 229 struct passwd passwd; 230 231 passwd.pw_uid = fUID; 232 passwd.pw_gid = fGID; 233 passwd.pw_name = store.AppendString(fName); 234 passwd.pw_passwd = store.AppendString(fPassword); 235 passwd.pw_dir = store.AppendString(fHome); 236 passwd.pw_shell = store.AppendString(fShell); 237 passwd.pw_gecos = store.AppendString(fRealName); 238 239 return store.AppendData(passwd); 240 } 241 242 spwd* WriteFlatShadowPwd(FlatStore& store) const 243 { 244 struct spwd spwd; 245 246 spwd.sp_namp = store.AppendString(fName); 247 spwd.sp_pwdp = store.AppendString(fShadowPassword); 248 spwd.sp_min = fMin; 249 spwd.sp_max = fMax; 250 spwd.sp_warn = fWarn; 251 spwd.sp_inact = fInactive; 252 spwd.sp_expire = fExpiration; 253 spwd.sp_flag = fFlags; 254 255 return store.AppendData(spwd); 256 } 257 258 status_t WriteToMessage(KMessage& message, bool addShadowPwd) 259 { 260 status_t error; 261 if ((error = message.AddInt32("uid", fUID)) != B_OK 262 || (error = message.AddInt32("gid", fGID)) != B_OK 263 || (error = message.AddString("name", fName.c_str())) != B_OK 264 || (error = message.AddString("password", fPassword.c_str())) 265 != B_OK 266 || (error = message.AddString("home", fHome.c_str())) != B_OK 267 || (error = message.AddString("shell", fShell.c_str())) != B_OK 268 || (error = message.AddString("real name", fRealName.c_str())) 269 != B_OK) { 270 return error; 271 } 272 273 if (!addShadowPwd) 274 return B_OK; 275 276 if ((error = message.AddString("shadow password", 277 fShadowPassword.c_str())) != B_OK 278 || (error = message.AddInt32("last changed", fLastChanged)) != B_OK 279 || (error = message.AddInt32("min", fMin)) != B_OK 280 || (error = message.AddInt32("max", fMax)) != B_OK 281 || (error = message.AddInt32("warn", fWarn)) != B_OK 282 || (error = message.AddInt32("inactive", fInactive)) != B_OK 283 || (error = message.AddInt32("expiration", fExpiration)) != B_OK 284 || (error = message.AddInt32("flags", fFlags)) != B_OK) { 285 return error; 286 } 287 288 return B_OK; 289 } 290 291 void WritePasswdLine(FILE* file) 292 { 293 fprintf(file, "%s:%s:%d:%d:%s:%s:%s\n", 294 fName.c_str(), fPassword.c_str(), (int)fUID, (int)fGID, 295 fRealName.c_str(), fHome.c_str(), fShell.c_str()); 296 } 297 298 void WriteShadowPwdLine(FILE* file) 299 { 300 fprintf(file, "%s:%s:%d:", fName.c_str(), fShadowPassword.c_str(), 301 fLastChanged); 302 303 // The following values are supposed to be printed as empty strings, 304 // if negative. 305 int values[5] = { fMin, fMax, fWarn, fInactive, fExpiration }; 306 for (int i = 0; i < 5; i++) { 307 if (values[i] >= 0) 308 fprintf(file, "%d", values[i]); 309 fprintf(file, ":"); 310 } 311 312 fprintf(file, "%d\n", fFlags); 313 } 314 315 private: 316 uid_t fUID; 317 gid_t fGID; 318 string fName; 319 string fPassword; 320 string fHome; 321 string fShell; 322 string fRealName; 323 string fShadowPassword; 324 int fLastChanged; 325 int fMin; 326 int fMax; 327 int fWarn; 328 int fInactive; 329 int fExpiration; 330 int fFlags; 331 }; 332 333 334 class AuthenticationManager::Group { 335 public: 336 Group(const char* name, const char* password, gid_t gid, 337 const char* const* members, int memberCount) 338 : 339 fGID(gid), 340 fName(name), 341 fPassword(password), 342 fMembers(new string[memberCount]), 343 fMemberCount(memberCount) 344 { 345 for (int i = 0; i < memberCount; i++) 346 fMembers[i] = members[i]; 347 } 348 349 ~Group() 350 { 351 delete[] fMembers; 352 } 353 354 const string& Name() const { return fName; } 355 const gid_t GID() const { return fGID; } 356 357 bool HasMember(const char* name) 358 { 359 for (int i = 0; i < fMemberCount; i++) { 360 if (fMembers[i] == name) 361 return true; 362 } 363 364 return false; 365 } 366 367 group* WriteFlatGroup(FlatStore& store) const 368 { 369 struct group group; 370 371 char* members[MAX_GROUP_MEMBER_COUNT + 1]; 372 for (int i = 0; i < fMemberCount; i++) 373 members[i] = store.AppendString(fMembers[i].c_str()); 374 members[fMemberCount] = (char*)-1; 375 376 group.gr_gid = fGID; 377 group.gr_name = store.AppendString(fName); 378 group.gr_passwd = store.AppendString(fPassword); 379 group.gr_mem = (char**)store.AppendData(members, 380 sizeof(char*) * (fMemberCount + 1), true); 381 382 return store.AppendData(group); 383 } 384 385 status_t WriteToMessage(KMessage& message) 386 { 387 status_t error; 388 if ((error = message.AddInt32("gid", fGID)) != B_OK 389 || (error = message.AddString("name", fName.c_str())) != B_OK 390 || (error = message.AddString("password", fPassword.c_str())) 391 != B_OK) { 392 return error; 393 } 394 395 for (int i = 0; i < fMemberCount; i++) { 396 if ((error = message.AddString("members", fMembers[i].c_str())) 397 != B_OK) { 398 return error; 399 } 400 } 401 402 return B_OK; 403 } 404 405 private: 406 gid_t fGID; 407 string fName; 408 string fPassword; 409 string* fMembers; 410 int fMemberCount; 411 }; 412 413 414 class AuthenticationManager::UserDB { 415 public: 416 status_t AddUser(User* user) 417 { 418 try { 419 fUsersByID[user->UID()] = user; 420 } catch (...) { 421 return B_NO_MEMORY; 422 } 423 424 try { 425 fUsersByName[user->Name()] = user; 426 } catch (...) { 427 fUsersByID.erase(fUsersByID.find(user->UID())); 428 return B_NO_MEMORY; 429 } 430 431 return B_OK; 432 } 433 434 User* UserByID(uid_t uid) const 435 { 436 map<uid_t, User*>::const_iterator it = fUsersByID.find(uid); 437 return (it == fUsersByID.end() ? NULL : it->second); 438 } 439 440 User* UserByName(const char* name) const 441 { 442 map<string, User*>::const_iterator it = fUsersByName.find(name); 443 return (it == fUsersByName.end() ? NULL : it->second); 444 } 445 446 int32 WriteFlatPasswdDB(FlatStore& store) const 447 { 448 int32 count = fUsersByID.size(); 449 450 size_t entriesSpace = sizeof(passwd*) * count; 451 size_t offset = store.ReserveSpace(entriesSpace, true); 452 passwd** entries = new passwd*[count]; 453 ArrayDeleter<passwd*> _(entries); 454 455 int32 index = 0; 456 for (map<uid_t, User*>::const_iterator it = fUsersByID.begin(); 457 it != fUsersByID.end(); ++it) { 458 entries[index++] = it->second->WriteFlatPasswd(store); 459 } 460 461 store.WriteData(offset, entries, entriesSpace); 462 463 return count; 464 } 465 466 int32 WriteFlatShadowDB(FlatStore& store) const 467 { 468 int32 count = fUsersByID.size(); 469 470 size_t entriesSpace = sizeof(spwd*) * count; 471 size_t offset = store.ReserveSpace(entriesSpace, true); 472 spwd** entries = new spwd*[count]; 473 ArrayDeleter<spwd*> _(entries); 474 475 int32 index = 0; 476 for (map<uid_t, User*>::const_iterator it = fUsersByID.begin(); 477 it != fUsersByID.end(); ++it) { 478 entries[index++] = it->second->WriteFlatShadowPwd(store); 479 } 480 481 store.WriteData(offset, entries, entriesSpace); 482 483 return count; 484 } 485 486 void WriteToDisk() 487 { 488 // rename the old files 489 string passwdBackup(kPasswdFile); 490 string shadowBackup(kShadowPwdFile); 491 passwdBackup += ".old"; 492 shadowBackup += ".old"; 493 494 rename(kPasswdFile, passwdBackup.c_str()); 495 rename(kShadowPwdFile, shadowBackup.c_str()); 496 // Don't check errors. We can't do anything anyway. 497 498 // open files 499 FILE* passwdFile = fopen(kPasswdFile, "w"); 500 if (passwdFile == NULL) { 501 debug_printf("REG: Failed to open passwd file \"%s\" for " 502 "writing: %s\n", kPasswdFile, strerror(errno)); 503 } 504 CObjectDeleter<FILE, int> _1(passwdFile, fclose); 505 506 FILE* shadowFile = fopen(kShadowPwdFile, "w"); 507 if (shadowFile == NULL) { 508 debug_printf("REG: Failed to open shadow passwd file \"%s\" for " 509 "writing: %s\n", kShadowPwdFile, strerror(errno)); 510 } 511 CObjectDeleter<FILE, int> _2(shadowFile, fclose); 512 513 // write users 514 for (map<uid_t, User*>::const_iterator it = fUsersByID.begin(); 515 it != fUsersByID.end(); ++it) { 516 User* user = it->second; 517 user->WritePasswdLine(passwdFile); 518 user->WriteShadowPwdLine(shadowFile); 519 } 520 } 521 522 private: 523 map<uid_t, User*> fUsersByID; 524 map<string, User*> fUsersByName; 525 }; 526 527 528 class AuthenticationManager::GroupDB { 529 public: 530 status_t AddGroup(Group* group) 531 { 532 try { 533 fGroupsByID[group->GID()] = group; 534 } catch (...) { 535 return B_NO_MEMORY; 536 } 537 538 try { 539 fGroupsByName[group->Name()] = group; 540 } catch (...) { 541 fGroupsByID.erase(fGroupsByID.find(group->GID())); 542 return B_NO_MEMORY; 543 } 544 545 return B_OK; 546 } 547 548 Group* GroupByID(gid_t gid) const 549 { 550 map<gid_t, Group*>::const_iterator it = fGroupsByID.find(gid); 551 return (it == fGroupsByID.end() ? NULL : it->second); 552 } 553 554 Group* GroupByName(const char* name) const 555 { 556 map<string, Group*>::const_iterator it = fGroupsByName.find(name); 557 return (it == fGroupsByName.end() ? NULL : it->second); 558 } 559 560 int32 GetUserGroups(const char* name, gid_t* groups, int maxCount) 561 { 562 int count = 0; 563 564 for (map<gid_t, Group*>::const_iterator it = fGroupsByID.begin(); 565 it != fGroupsByID.end(); ++it) { 566 Group* group = it->second; 567 if (group->HasMember(name)) { 568 if (count < maxCount) 569 groups[count] = group->GID(); 570 count++; 571 } 572 } 573 574 return count; 575 } 576 577 578 int32 WriteFlatGroupDB(FlatStore& store) const 579 { 580 int32 count = fGroupsByID.size(); 581 582 size_t entriesSpace = sizeof(group*) * count; 583 size_t offset = store.ReserveSpace(entriesSpace, true); 584 group** entries = new group*[count]; 585 ArrayDeleter<group*> _(entries); 586 587 int32 index = 0; 588 for (map<gid_t, Group*>::const_iterator it = fGroupsByID.begin(); 589 it != fGroupsByID.end(); ++it) { 590 entries[index++] = it->second->WriteFlatGroup(store); 591 } 592 593 store.WriteData(offset, entries, entriesSpace); 594 595 return count; 596 } 597 598 private: 599 map<uid_t, Group*> fGroupsByID; 600 map<string, Group*> fGroupsByName; 601 }; 602 603 604 AuthenticationManager::AuthenticationManager() 605 : 606 fRequestPort(-1), 607 fRequestThread(-1), 608 fUserDB(NULL), 609 fGroupDB(NULL), 610 fPasswdDBReply(NULL), 611 fGroupDBReply(NULL), 612 fShadowPwdDBReply(NULL) 613 { 614 } 615 616 617 AuthenticationManager::~AuthenticationManager() 618 { 619 // delete port and wait for the request thread to finish 620 if (fRequestPort >= 0) 621 delete_port(fRequestPort); 622 623 status_t dummy; 624 wait_for_thread(fRequestThread, &dummy); 625 626 delete fUserDB; 627 delete fGroupDB; 628 delete fPasswdDBReply; 629 delete fGroupDBReply; 630 delete fShadowPwdDBReply; 631 } 632 633 634 status_t 635 AuthenticationManager::Init() 636 { 637 fUserDB = new(std::nothrow) UserDB; 638 fGroupDB = new(std::nothrow) GroupDB; 639 fPasswdDBReply = new(std::nothrow) KMessage(1); 640 fGroupDBReply = new(std::nothrow) KMessage(1); 641 fShadowPwdDBReply = new(std::nothrow) KMessage(1); 642 643 if (fUserDB == NULL || fGroupDB == NULL || fPasswdDBReply == NULL 644 || fGroupDBReply == NULL || fShadowPwdDBReply == NULL) { 645 return B_NO_MEMORY; 646 } 647 648 fRequestPort = create_port(100, REGISTRAR_AUTHENTICATION_PORT_NAME); 649 if (fRequestPort < 0) 650 return fRequestPort; 651 652 fRequestThread = spawn_thread(&_RequestThreadEntry, 653 "authentication manager", B_NORMAL_PRIORITY, this); 654 if (fRequestThread < 0) 655 return fRequestThread; 656 657 resume_thread(fRequestThread); 658 659 return B_OK; 660 } 661 662 663 status_t 664 AuthenticationManager::_RequestThreadEntry(void* data) 665 { 666 return ((AuthenticationManager*)data)->_RequestThread(); 667 } 668 669 670 status_t 671 AuthenticationManager::_RequestThread() 672 { 673 // read the DB files 674 _InitPasswdDB(); 675 _InitGroupDB(); 676 _InitShadowPwdDB(); 677 678 // get our team ID 679 team_id registrarTeam = -1; 680 { 681 thread_info info; 682 if (get_thread_info(find_thread(NULL), &info) == B_OK) 683 registrarTeam = info.team; 684 } 685 686 // request loop 687 while (true) { 688 KMessage message; 689 port_message_info messageInfo; 690 status_t error = message.ReceiveFrom(fRequestPort, -1, &messageInfo); 691 if (error != B_OK) 692 return B_OK; 693 694 bool isRoot = (messageInfo.sender == 0); 695 696 switch (message.What()) { 697 case B_REG_GET_PASSWD_DB: 698 { 699 // lazily build the reply 700 try { 701 if (fPasswdDBReply->What() == 1) { 702 FlatStore store; 703 int32 count = fUserDB->WriteFlatPasswdDB(store); 704 if (fPasswdDBReply->AddInt32("count", count) != B_OK 705 || fPasswdDBReply->AddData("entries", B_RAW_TYPE, 706 store.Buffer(), store.BufferLength(), 707 false) != B_OK) { 708 error = B_NO_MEMORY; 709 } 710 711 fPasswdDBReply->SetWhat(0); 712 } 713 } catch (...) { 714 error = B_NO_MEMORY; 715 } 716 717 if (error == B_OK) { 718 message.SendReply(fPasswdDBReply, -1, -1, 0, registrarTeam); 719 } else { 720 fPasswdDBReply->SetTo(1); 721 KMessage reply(error); 722 message.SendReply(&reply, -1, -1, 0, registrarTeam); 723 } 724 725 break; 726 } 727 728 case B_REG_GET_GROUP_DB: 729 { 730 // lazily build the reply 731 try { 732 if (fGroupDBReply->What() == 1) { 733 FlatStore store; 734 int32 count = fGroupDB->WriteFlatGroupDB(store); 735 if (fGroupDBReply->AddInt32("count", count) != B_OK 736 || fGroupDBReply->AddData("entries", B_RAW_TYPE, 737 store.Buffer(), store.BufferLength(), 738 false) != B_OK) { 739 error = B_NO_MEMORY; 740 } 741 742 fGroupDBReply->SetWhat(0); 743 } 744 } catch (...) { 745 error = B_NO_MEMORY; 746 } 747 748 if (error == B_OK) { 749 message.SendReply(fGroupDBReply, -1, -1, 0, registrarTeam); 750 } else { 751 fGroupDBReply->SetTo(1); 752 KMessage reply(error); 753 message.SendReply(&reply, -1, -1, 0, registrarTeam); 754 } 755 756 break; 757 } 758 759 760 case B_REG_GET_SHADOW_PASSWD_DB: 761 { 762 // only root may see the shadow passwd 763 if (!isRoot) 764 error = EPERM; 765 766 // lazily build the reply 767 try { 768 if (error == B_OK && fShadowPwdDBReply->What() == 1) { 769 FlatStore store; 770 int32 count = fUserDB->WriteFlatShadowDB(store); 771 if (fShadowPwdDBReply->AddInt32("count", count) != B_OK 772 || fShadowPwdDBReply->AddData("entries", B_RAW_TYPE, 773 store.Buffer(), store.BufferLength(), 774 false) != B_OK) { 775 error = B_NO_MEMORY; 776 } 777 778 fShadowPwdDBReply->SetWhat(0); 779 } 780 } catch (...) { 781 error = B_NO_MEMORY; 782 } 783 784 if (error == B_OK) { 785 message.SendReply(fShadowPwdDBReply, -1, -1, 0, 786 registrarTeam); 787 } else { 788 fShadowPwdDBReply->SetTo(1); 789 KMessage reply(error); 790 message.SendReply(&reply, -1, -1, 0, registrarTeam); 791 } 792 793 break; 794 } 795 796 case B_REG_GET_USER: 797 { 798 User* user = NULL; 799 int32 uid; 800 const char* name; 801 802 // find user 803 if (message.FindInt32("uid", &uid) == B_OK) { 804 user = fUserDB->UserByID(uid); 805 } else if (message.FindString("name", &name) == B_OK) { 806 user = fUserDB->UserByName(name); 807 } else { 808 error = B_BAD_VALUE; 809 } 810 811 if (error == B_OK && user == NULL) 812 error = ENOENT; 813 814 bool getShadowPwd = message.GetBool("shadow", false); 815 816 // only root may see the shadow passwd 817 if (error == B_OK && getShadowPwd && !isRoot) 818 error = EPERM; 819 820 // add user to message 821 KMessage reply; 822 if (error == B_OK) 823 error = user->WriteToMessage(reply, getShadowPwd); 824 825 // send reply 826 reply.SetWhat(error); 827 message.SendReply(&reply, -1, -1, 0, registrarTeam); 828 829 break; 830 } 831 832 case B_REG_GET_GROUP: 833 { 834 Group* group = NULL; 835 int32 gid; 836 const char* name; 837 838 // find group 839 if (message.FindInt32("gid", &gid) == B_OK) { 840 group = fGroupDB->GroupByID(gid); 841 } else if (message.FindString("name", &name) == B_OK) { 842 group = fGroupDB->GroupByName(name); 843 } else { 844 error = B_BAD_VALUE; 845 } 846 847 if (error == B_OK && group == NULL) 848 error = ENOENT; 849 850 // add group to message 851 KMessage reply; 852 if (error == B_OK) 853 error = group->WriteToMessage(reply); 854 855 // send reply 856 reply.SetWhat(error); 857 message.SendReply(&reply, -1, -1, 0, registrarTeam); 858 859 break; 860 } 861 862 case B_REG_GET_USER_GROUPS: 863 { 864 // get user name 865 const char* name; 866 int32 maxCount; 867 if (message.FindString("name", &name) != B_OK 868 || message.FindInt32("max count", &maxCount) != B_OK 869 || maxCount <= 0) { 870 error = B_BAD_VALUE; 871 } 872 873 // get groups 874 gid_t groups[NGROUPS_MAX + 1]; 875 int32 count = 0; 876 if (error == B_OK) { 877 maxCount = min_c(maxCount, NGROUPS_MAX + 1); 878 count = fGroupDB->GetUserGroups(name, groups, maxCount); 879 } 880 881 // add groups to message 882 KMessage reply; 883 if (error == B_OK) { 884 if (reply.AddInt32("count", count) != B_OK 885 || reply.AddData("groups", B_INT32_TYPE, 886 groups, min_c(maxCount, count) * sizeof(gid_t), 887 false) != B_OK) { 888 error = B_NO_MEMORY; 889 } 890 } 891 892 // send reply 893 reply.SetWhat(error); 894 message.SendReply(&reply, -1, -1, 0, registrarTeam); 895 896 break; 897 } 898 899 case B_REG_UPDATE_USER: 900 { 901 // find user 902 User* user = NULL; 903 int32 uid; 904 const char* name; 905 906 if (message.FindInt32("uid", &uid) == B_OK) { 907 user = fUserDB->UserByID(uid); 908 } else if (message.FindString("name", &name) == B_OK) { 909 user = fUserDB->UserByName(name); 910 } else { 911 error = B_BAD_VALUE; 912 } 913 914 // only can change anything 915 if (error == B_OK && !isRoot) 916 error = EPERM; 917 918 // check addUser vs. existing user 919 bool addUser = message.GetBool("add user", false); 920 if (error == B_OK) { 921 if (addUser) { 922 if (user != NULL) 923 error = EEXIST; 924 } else if (user == NULL) 925 error = ENOENT; 926 } 927 928 // apply all changes 929 if (error == B_OK) { 930 // clone the user object and update it from the message 931 User* oldUser = user; 932 user = NULL; 933 try { 934 user = (oldUser != NULL ? new User(*oldUser) 935 : new User); 936 user->UpdateFromMessage(message); 937 938 // uid and name should remain the same 939 if (oldUser != NULL) { 940 if (oldUser->UID() != user->UID() 941 || oldUser->Name() != user->Name()) { 942 error = B_BAD_VALUE; 943 } 944 } 945 946 // replace the old user and write DBs to disk 947 if (error == B_OK) { 948 fUserDB->AddUser(user); 949 fUserDB->WriteToDisk(); 950 fPasswdDBReply->SetTo(1); 951 fShadowPwdDBReply->SetTo(1); 952 } 953 } catch (...) { 954 error = B_NO_MEMORY; 955 } 956 957 if (error == B_OK) 958 delete oldUser; 959 else 960 delete user; 961 } 962 963 // send reply 964 KMessage reply; 965 reply.SetWhat(error); 966 message.SendReply(&reply, -1, -1, 0, registrarTeam); 967 968 break; 969 } 970 case B_REG_UPDATE_GROUP: 971 debug_printf("B_REG_UPDATE_GROUP done: currently unsupported!\n"); 972 break; 973 default: 974 debug_printf("REG: invalid message: %lu\n", message.What()); 975 976 } 977 } 978 } 979 980 981 status_t 982 AuthenticationManager::_InitPasswdDB() 983 { 984 FILE* file = fopen(kPasswdFile, "r"); 985 if (file == NULL) { 986 debug_printf("REG: Failed to open passwd DB file \"%s\": %s\n", 987 kPasswdFile, strerror(errno)); 988 return errno; 989 } 990 CObjectDeleter<FILE, int> _(file, fclose); 991 992 char lineBuffer[LINE_MAX]; 993 while (char* line = fgets(lineBuffer, sizeof(lineBuffer), file)) { 994 if (strlen(line) == 0) 995 continue; 996 997 char* name; 998 char* password; 999 uid_t uid; 1000 gid_t gid; 1001 char* home; 1002 char* shell; 1003 char* realName; 1004 1005 status_t error = parse_passwd_line(line, name, password, uid, gid, 1006 home, shell, realName); 1007 if (error != B_OK) { 1008 debug_printf("REG: Unparsable line in passwd DB file: \"%s\"\n", 1009 strerror(errno)); 1010 continue; 1011 } 1012 1013 User* user = NULL; 1014 try { 1015 user = new User(name, password, uid, gid, home, shell, realName); 1016 } catch (...) { 1017 } 1018 1019 if (user == NULL || fUserDB->AddUser(user) != B_OK) { 1020 delete user; 1021 debug_printf("REG: Out of memory\n"); 1022 return B_NO_MEMORY; 1023 } 1024 } 1025 1026 return B_OK; 1027 } 1028 1029 1030 status_t 1031 AuthenticationManager::_InitGroupDB() 1032 { 1033 FILE* file = fopen(kGroupFile, "r"); 1034 if (file == NULL) { 1035 debug_printf("REG: Failed to open group DB file \"%s\": %s\n", 1036 kGroupFile, strerror(errno)); 1037 return errno; 1038 } 1039 CObjectDeleter<FILE, int> _(file, fclose); 1040 1041 char lineBuffer[LINE_MAX]; 1042 while (char* line = fgets(lineBuffer, sizeof(lineBuffer), file)) { 1043 if (strlen(line) == 0) 1044 continue; 1045 1046 char* name; 1047 char* password; 1048 gid_t gid; 1049 char* members[MAX_GROUP_MEMBER_COUNT]; 1050 int memberCount; 1051 1052 1053 status_t error = parse_group_line(line, name, password, gid, members, 1054 memberCount); 1055 if (error != B_OK) { 1056 debug_printf("REG: Unparsable line in group DB file: \"%s\"\n", 1057 strerror(errno)); 1058 continue; 1059 } 1060 1061 Group* group = NULL; 1062 try { 1063 group = new Group(name, password, gid, members, memberCount); 1064 } catch (...) { 1065 } 1066 1067 if (group == NULL || fGroupDB->AddGroup(group) != B_OK) { 1068 delete group; 1069 debug_printf("REG: Out of memory\n"); 1070 return B_NO_MEMORY; 1071 } 1072 } 1073 1074 return B_OK; 1075 } 1076 1077 1078 status_t 1079 AuthenticationManager::_InitShadowPwdDB() 1080 { 1081 FILE* file = fopen(kShadowPwdFile, "r"); 1082 if (file == NULL) { 1083 debug_printf("REG: Failed to open shadow passwd DB file \"%s\": %s\n", 1084 kShadowPwdFile, strerror(errno)); 1085 return errno; 1086 } 1087 CObjectDeleter<FILE, int> _(file, fclose); 1088 1089 char lineBuffer[LINE_MAX]; 1090 while (char* line = fgets(lineBuffer, sizeof(lineBuffer), file)) { 1091 if (strlen(line) == 0) 1092 continue; 1093 1094 char* name; 1095 char* password; 1096 int lastChanged; 1097 int min; 1098 int max; 1099 int warn; 1100 int inactive; 1101 int expiration; 1102 int flags; 1103 1104 status_t error = parse_shadow_pwd_line(line, name, password, 1105 lastChanged, min, max, warn, inactive, expiration, flags); 1106 if (error != B_OK) { 1107 debug_printf("REG: Unparsable line in shadow passwd DB file: " 1108 "\"%s\"\n", strerror(errno)); 1109 continue; 1110 } 1111 1112 User* user = fUserDB->UserByName(name); 1113 if (user == NULL) { 1114 debug_printf("REG: shadow pwd entry for unknown user \"%s\"\n", 1115 name); 1116 continue; 1117 } 1118 1119 try { 1120 user->SetShadowInfo(password, lastChanged, min, max, warn, inactive, 1121 expiration, flags); 1122 } catch (...) { 1123 debug_printf("REG: Out of memory\n"); 1124 return B_NO_MEMORY; 1125 } 1126 } 1127 1128 return B_OK; 1129 } 1130