Changeset 101233 in vbox for trunk/src/VBox/Additions/common
- Timestamp:
- Sep 22, 2023 7:54:00 AM (20 months ago)
- svn:sync-xref-src-repo-rev:
- 159216
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp
r98103 r101233 165 165 /** @name ConsoleKit defines (taken from 0.4.5). 166 166 * @{ */ 167 # define CK_NAME "org.freedesktop.ConsoleKit" 168 # define CK_PATH "/org/freedesktop/ConsoleKit" 167 # define CK_NAME "org.freedesktop.ConsoleKit" /* unused */ 168 # define CK_PATH "/org/freedesktop/ConsoleKit" /* unused */ 169 169 # define CK_INTERFACE "org.freedesktop.ConsoleKit" 170 170 # define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" 171 171 # define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager" 172 # define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" 172 # define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" /* unused */ 173 173 # define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session" 174 /** @} */ 175 /** @name systemd-logind defines 176 * @{ */ 177 # define SYSTEMD_LOGIN_INTERFACE "org.freedesktop.login1" 178 # define SYSTEMD_LOGIN_PATH "/org/freedesktop/login1" 179 # define SYSTEMD_LOGIN_MANAGER_INTERFACE "org.freedesktop.login1.Manager" 180 # define SYSTEMD_LOGIN_SESSION_INTERFACE "org.freedesktop.login1.Session" 174 181 /** @} */ 175 182 #endif … … 538 545 #if defined(VBOX_WITH_DBUS) && defined(RT_OS_LINUX) /* Not yet for Solaris/FreeBSB. */ 539 546 /* 540 * Simple wrapper to work around compiler-specific va_list madness.547 * Simple wrappers to work around compiler-specific va_list madness. 541 548 */ 542 549 static dbus_bool_t vboxService_dbus_message_get_args(DBusMessage *message, DBusError *error, int first_arg_type, ...) … … 548 555 return ret; 549 556 } 557 558 static dbus_bool_t vboxService_dbus_message_append_args(DBusMessage *message, int first_arg_type, ...) 559 { 560 va_list va; 561 va_start(va, first_arg_type); 562 dbus_bool_t ret = dbus_message_append_args_valist(message, first_arg_type, va); 563 va_end(va); 564 return ret; 565 } 566 567 #ifndef DBUS_TYPE_VARIANT 568 #define DBUS_TYPE_VARIANT ((int) 'v') 550 569 #endif 551 570 /* 571 * Wrapper to dig values out of dbus replies, which are contained in 572 * a 'variant' and must be iterated into twice. 573 * 574 * Returns true if it thinks it got a value; false if not. 575 * 576 * This does various error checking so the caller can skip it: 577 * - whether a DBusError is set 578 * - whether the DBusMessage is valid 579 * - whether we actually got a 'variant' 580 * - whether we got the type the caller's looking for 581 */ 582 static bool vboxService_dbus_unpack_variant_reply(DBusError *error, DBusMessage *pReply, char pType, void *pValue) { 583 if (dbus_error_is_set(error)) { 584 VGSvcError("dbus_unpack_variant_reply: dbus returned error '%s'\n", error->message); 585 dbus_error_free(error); 586 } else if (pReply) { 587 DBusMessageIter iterMsg; 588 int iterType; 589 dbus_message_iter_init(pReply, &iterMsg); 590 iterType = dbus_message_iter_get_arg_type(&iterMsg); 591 if (iterType == DBUS_TYPE_VARIANT) { 592 DBusMessageIter iterValueMsg; 593 int iterValueType; 594 dbus_message_iter_recurse(&iterMsg, &iterValueMsg); 595 iterValueType = dbus_message_iter_get_arg_type(&iterValueMsg); 596 if (iterValueType == pType) { 597 dbus_message_iter_get_basic(&iterValueMsg, pValue); 598 return true; 599 } 600 } 601 } 602 return false; 603 } 604 605 /* 606 * Wrapper to NULL out the DBusMessage pointer while discarding it. 607 * DBus API is multi-threaded and can have multiple concurrent accessors. 608 * Our use here is single-threaded and can never have multiple accessors. 609 */ 610 static void vboxService_dbus_message_discard(DBusMessage **ppMsg) 611 { 612 if (ppMsg && *ppMsg) { 613 #if defined(ICKY_REFCOUNT_GRUBBING) 614 { 615 /* The DBusMessage Refcount private field isn't externally accessible. 616 * We want to check it for debug / assert purposes. 617 */ 618 uint32_t *pcRefCnt = (uint32_t *)(*ppMsg); 619 if (*p == 0) { 620 VGSvcVerbose(1, "dbus_message_discard: unref %p whose refcnt is 0 (expected 1) -- this would have been a double-free\n", ppMsg); 621 *ppMsg = NULL; 622 return; 623 } else if (*p != 1) { 624 VGSvcVerbose(1, "dbus_message_discard: unref %p whose refcnt is %d (expected 1)\n", ppMsg, *p); 625 } 626 } 627 #endif /* ICKY_REFCOUNT_GRUBBING */ 628 dbus_message_unref(*ppMsg); 629 *ppMsg = NULL; 630 } 631 } 632 #endif 633 634 635 /* 636 * Add a user to the list of active users (while ignoring duplicates 637 * and dynamically maintaining the list storage) 638 */ 639 #define USER_LIST_CHUNK_SIZE 32 640 static uint32_t cUsersInList; 641 static uint32_t cListSize; 642 static char **papszUsers; 643 644 static void vgsvcVMInfoAddUserToList(const char *name, const char *src) 645 { 646 int rc; 647 bool fFound = false; 648 for (uint32_t idx = 0; idx < cUsersInList && !fFound; idx++) 649 fFound = strncmp(papszUsers[idx], name, 32) == 0; 650 VGSvcVerbose(5, "LoggedInUsers: Asked to add user '%s' from '%s' to list (already in list = %lu)\n", name, src, fFound); 651 if (!fFound) 652 { 653 if (cUsersInList + 1 > cListSize) 654 { 655 VGSvcVerbose(5, "LoggedInUsers: increase user list size from %lu to %lu\n", cListSize, cListSize + USER_LIST_CHUNK_SIZE); 656 cListSize += USER_LIST_CHUNK_SIZE; 657 void *pvNew = RTMemRealloc(papszUsers, cListSize * sizeof(char*)); 658 AssertReturnVoidStmt(pvNew, cListSize -= USER_LIST_CHUNK_SIZE); 659 papszUsers = (char **)pvNew; 660 } 661 VGSvcVerbose(4, "LoggedInUsers: Adding user '%s' from '%s' to list (size = %lu, count = %lu)\n", name, src, cListSize, cUsersInList); 662 rc = RTStrDupEx(&papszUsers[cUsersInList], name); 663 if (!RT_FAILURE(rc)) 664 cUsersInList++; 665 } 666 } 552 667 553 668 /** … … 558 673 int rc; 559 674 char *pszUserList = NULL; 560 uint32_t cUsersInList = 0; 675 676 cUsersInList = 0; 561 677 562 678 #ifdef RT_OS_WINDOWS … … 580 696 setutxent(); 581 697 utmpx *ut_user; 582 uint32_t cListSize = 32;698 cListSize = USER_LIST_CHUNK_SIZE; 583 699 584 700 /* Allocate a first array to hold 32 users max. */ 585 char **papszUsers = (char **)RTMemAllocZ(cListSize * sizeof(char *));701 papszUsers = (char **)RTMemAllocZ(cListSize * sizeof(char *)); 586 702 if (papszUsers) 587 703 rc = VINF_SUCCESS; … … 600 716 ut_user->ut_user, ut_user->ut_type, ut_user->ut_pid, ut_user->ut_session); 601 717 # endif 602 if (cUsersInList > cListSize)603 {604 cListSize += 32;605 void *pvNew = RTMemRealloc(papszUsers, cListSize * sizeof(char*));606 AssertBreakStmt(pvNew, cListSize -= 32);607 papszUsers = (char **)pvNew;608 }609 718 610 719 /* Make sure we don't add user names which are not … … 612 721 if (ut_user->ut_type == USER_PROCESS) /* Regular user process. */ 613 722 { 614 bool fFound = false; 615 for (uint32_t i = 0; i < cUsersInList && !fFound; i++) 616 fFound = strncmp(papszUsers[i], ut_user->ut_user, sizeof(ut_user->ut_user)) == 0; 617 618 if (!fFound) 619 { 620 VGSvcVerbose(4, "Adding user '%s' (type: %d) to list\n", ut_user->ut_user, ut_user->ut_type); 621 622 rc = RTStrDupEx(&papszUsers[cUsersInList], (const char *)ut_user->ut_user); 623 if (RT_FAILURE(rc)) 624 break; 625 cUsersInList++; 626 } 723 vgsvcVMInfoAddUserToList(ut_user->ut_user, "utmpx"); 627 724 } 628 725 } … … 636 733 if (RT_SUCCESS(rc2)) 637 734 { 735 /* Handle desktop sessions using systemd-logind. */ 736 VGSvcVerbose(4, "Checking systemd-logind sessions ...\n"); 737 fHaveLibDbus = true; 738 dbus_error_init(&dbErr); 739 pConnection = dbus_bus_get(DBUS_BUS_SYSTEM, &dbErr); 740 } 741 742 if ( pConnection 743 && !dbus_error_is_set(&dbErr)) 744 { 745 // TODO: is there some Less Horrible Way(tm) to access dbus? 746 /* Get all available sessions. */ 747 /* like `busctl call org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager ListSessions` */ 748 DBusMessage *pMsgSessions = dbus_message_new_method_call(SYSTEMD_LOGIN_INTERFACE, 749 SYSTEMD_LOGIN_PATH, 750 SYSTEMD_LOGIN_MANAGER_INTERFACE, 751 "ListSessions"); 752 if ( pMsgSessions 753 && dbus_message_get_type(pMsgSessions) == DBUS_MESSAGE_TYPE_METHOD_CALL) 754 { 755 DBusMessage *pReplySessions = dbus_connection_send_with_reply_and_block(pConnection, 756 pMsgSessions, 30 * 1000 /* 30s timeout */, 757 &dbErr); 758 if ( pReplySessions 759 && !dbus_error_is_set(&dbErr)) 760 { 761 /* dbus_message_new_method_call() returns a DBusMessage, which we must iterate to get the returned value */ 762 DBusMessageIter messageIterMsg; 763 int messageIterType; 764 dbus_message_iter_init(pReplySessions, &messageIterMsg); 765 while ((messageIterType = dbus_message_iter_get_arg_type (&messageIterMsg)) != DBUS_TYPE_INVALID) { 766 if (messageIterType == DBUS_TYPE_ARRAY) { 767 /* "ListSessions" returns an array, which we must iterate to get the array elements */ 768 DBusMessageIter arrayIterMsg; 769 int arrayIterType; 770 dbus_message_iter_recurse(&messageIterMsg, &arrayIterMsg); 771 while ((arrayIterType = dbus_message_iter_get_arg_type (&arrayIterMsg)) != DBUS_TYPE_INVALID) { 772 if (arrayIterType == DBUS_TYPE_STRUCT) { 773 /* The array elements are structs, which we must iterate to get the struct elements */ 774 DBusMessageIter structIterMsg; 775 int structIterType; 776 dbus_message_iter_recurse(&arrayIterMsg, &structIterMsg); 777 while ((structIterType = dbus_message_iter_get_arg_type (&structIterMsg)) != DBUS_TYPE_INVALID) { 778 if (structIterType == DBUS_TYPE_OBJECT_PATH) { 779 /* We are interested only in the "object path" struct element */ 780 const char *objectPath; 781 dbus_message_iter_get_basic(&structIterMsg, &objectPath); 782 const char *pInterface = SYSTEMD_LOGIN_SESSION_INTERFACE; 783 /* Create and send a new dbus query asking for that session's details */ 784 DBusMessage *pMsgSession = dbus_message_new_method_call(SYSTEMD_LOGIN_INTERFACE, 785 objectPath, 786 "org.freedesktop.DBus.Properties", 787 "Get"); 788 if ( pMsgSession 789 && dbus_message_get_type(pMsgSession) == DBUS_MESSAGE_TYPE_METHOD_CALL) { 790 const char *pPropertyActive = "Active"; 791 vboxService_dbus_message_append_args(pMsgSession, 792 DBUS_TYPE_STRING, &pInterface, 793 DBUS_TYPE_STRING, &pPropertyActive, 794 DBUS_TYPE_INVALID, 0); 795 /* like `busctl get-property org.freedesktop.login1 %s org.freedesktop.login1.Session Active` %(objectPath) */ 796 DBusMessage *pReplySession = dbus_connection_send_with_reply_and_block( 797 pConnection, 798 pMsgSession, 799 -1, 800 &dbErr); 801 int sessionPropertyActiveValue; 802 if ( vboxService_dbus_unpack_variant_reply( 803 &dbErr, 804 pReplySession, 805 DBUS_TYPE_BOOLEAN, 806 &sessionPropertyActiveValue) 807 && sessionPropertyActiveValue) { 808 DBusMessage *pMsgSession2 = dbus_message_new_method_call(SYSTEMD_LOGIN_INTERFACE, 809 objectPath, 810 "org.freedesktop.DBus.Properties", 811 "Get"); 812 const char *pPropertyName = "Name"; 813 if ( pMsgSession2 814 && dbus_message_get_type(pMsgSession2) == DBUS_MESSAGE_TYPE_METHOD_CALL) { 815 vboxService_dbus_message_append_args(pMsgSession2, 816 DBUS_TYPE_STRING, &pInterface, 817 DBUS_TYPE_STRING, &pPropertyName, 818 DBUS_TYPE_INVALID, 0); 819 /* like `busctl get-property org.freedesktop.login1 %s org.freedesktop.login1.Session Name` %(objectPath) */ 820 DBusMessage *pReplyName = dbus_connection_send_with_reply_and_block( 821 pConnection, 822 pMsgSession2, 823 -1, 824 &dbErr); 825 const char *sessionPropertyNameValue; 826 if ( vboxService_dbus_unpack_variant_reply( 827 &dbErr, 828 pReplyName, 829 DBUS_TYPE_STRING, 830 &sessionPropertyNameValue) 831 && sessionPropertyNameValue) 832 vgsvcVMInfoAddUserToList(sessionPropertyNameValue, "systemd-logind"); 833 vboxService_dbus_message_discard(&pReplyName); 834 } 835 vboxService_dbus_message_discard(&pMsgSession2); 836 } 837 vboxService_dbus_message_discard(&pReplySession); 838 } 839 vboxService_dbus_message_discard(&pMsgSession); 840 } 841 dbus_message_iter_next (&structIterMsg); 842 } 843 } 844 dbus_message_iter_next (&arrayIterMsg); 845 } 846 } 847 dbus_message_iter_next (&messageIterMsg); 848 } 849 vboxService_dbus_message_discard(&pReplySessions); 850 } 851 } 852 else 853 { 854 static int s_iBitchedAboutSystemdLogind = 0; 855 if (s_iBitchedAboutSystemdLogind < 3) 856 { 857 s_iBitchedAboutSystemdLogind++; 858 VGSvcError("Unable to invoke systemd-logind (%d/3) -- maybe not installed / used? Error: %s\n", 859 s_iBitchedAboutSystemdLogind, 860 dbus_error_is_set(&dbErr) ? dbErr.message : "No error information available"); 861 } 862 } 863 864 vboxService_dbus_message_discard(&pMsgSessions); 865 if (dbus_error_is_set(&dbErr)) 866 { 867 dbus_error_free(&dbErr); 868 } 869 } 870 if (RT_SUCCESS(rc2)) 871 { 638 872 /* Handle desktop sessions using ConsoleKit. */ 639 873 VGSvcVerbose(4, "Checking ConsoleKit sessions ...\n"); 640 874 fHaveLibDbus = true; 641 875 dbus_error_init(&dbErr); 876 /* TODO: should this be dbus_connection_open() (and below, dbus_connection_unref())? */ 642 877 pConnection = dbus_bus_get(DBUS_BUS_SYSTEM, &dbErr); 643 878 } … … 647 882 { 648 883 /* Get all available sessions. */ 649 /** @todo r=bird: What's the point of hardcoding things here when we've taken the pain of defining CK_XXX constants at the top of the file (or vice versa)? */ 650 DBusMessage *pMsgSessions = dbus_message_new_method_call("org.freedesktop.ConsoleKit", 651 "/org/freedesktop/ConsoleKit/Manager", 652 "org.freedesktop.ConsoleKit.Manager", 884 DBusMessage *pMsgSessions = dbus_message_new_method_call(CK_INTERFACE, 885 CK_MANAGER_PATH, 886 CK_MANAGER_INTERFACE, 653 887 "GetSessions"); 654 888 if ( pMsgSessions … … 677 911 /* Only respect active sessions .*/ 678 912 bool fActive = false; 679 DBusMessage *pMsgSessionActive = dbus_message_new_method_call( "org.freedesktop.ConsoleKit",913 DBusMessage *pMsgSessionActive = dbus_message_new_method_call(CK_INTERFACE, 680 914 *ppszCurSession, 681 "org.freedesktop.ConsoleKit.Session",915 CK_SESSION_INTERFACE, 682 916 "IsActive"); 683 917 if ( pMsgSessionActive … … 701 935 } 702 936 703 if (pReplySessionActive)704 dbus_message_unref(pReplySessionActive);705 937 } 706 707 if (pMsgSessionActive) 708 dbus_message_unref(pMsgSessionActive); 938 /* TODO: clean up if &dbErr */ 939 vboxService_dbus_message_discard(&pReplySessionActive); 940 941 vboxService_dbus_message_discard(&pMsgSessionActive); 709 942 } 710 943 … … 714 947 /* *ppszCurSession now contains the object path 715 948 * (e.g. "/org/freedesktop/ConsoleKit/Session1"). */ 716 DBusMessage *pMsgUnixUser = dbus_message_new_method_call( "org.freedesktop.ConsoleKit",949 DBusMessage *pMsgUnixUser = dbus_message_new_method_call(CK_INTERFACE, 717 950 *ppszCurSession, 718 "org.freedesktop.ConsoleKit.Session",951 CK_SESSION_INTERFACE, 719 952 "GetUnixUser"); 720 953 if ( fActive … … 737 970 dbus_message_iter_get_basic(&itMsg, &uid); 738 971 739 /** @todo Add support for getting UID_MIN (/etc/login.defs on740 * Debian). */741 uint32_t uid_min = 1000;742 743 972 /* Look up user name (realname) from uid. */ 744 973 setpwent(); … … 747 976 && ppwEntry->pw_name) 748 977 { 749 if (ppwEntry->pw_uid >= uid_min /* Only respect users, not daemons etc. */)750 {751 978 VGSvcVerbose(4, "ConsoleKit: session '%s' -> %s (uid: %RU32)\n", 752 979 *ppszCurSession, ppwEntry->pw_name, uid); 753 754 bool fFound = false; 755 for (uint32_t i = 0; i < cUsersInList && !fFound; i++) 756 fFound = strcmp(papszUsers[i], ppwEntry->pw_name) == 0; 757 758 if (!fFound) 759 { 760 VGSvcVerbose(4, "ConsoleKit: adding user '%s' to list\n", ppwEntry->pw_name); 761 762 rc = RTStrDupEx(&papszUsers[cUsersInList], (const char *)ppwEntry->pw_name); 763 if (RT_FAILURE(rc)) 764 break; 765 cUsersInList++; 766 } 767 } 768 /* else silently ignore the user */ 980 vgsvcVMInfoAddUserToList(ppwEntry->pw_name, "ConsoleKit"); 769 981 } 770 982 else … … 774 986 AssertMsgFailed(("ConsoleKit: GetUnixUser returned a wrong argument type\n")); 775 987 } 776 777 if (pReplyUnixUser) 778 dbus_message_unref(pReplyUnixUser);988 /* TODO: clean up if &dbErr */ 989 990 vboxService_dbus_message_discard(&pReplyUnixUser); 779 991 } 780 992 else if (fActive) /* don't bitch about inactive users */ … … 790 1002 } 791 1003 792 if (pMsgUnixUser) 793 dbus_message_unref(pMsgUnixUser); 1004 vboxService_dbus_message_discard(&pMsgUnixUser); 794 1005 } 795 1006 … … 800 1011 dbus_message_get_type(pMsgSessions), 801 1012 dbus_error_is_set(&dbErr) ? dbErr.message : "No error information available"); 802 dbus_message_unref(pReplySessions); 803 } 804 805 if (pMsgSessions) 806 { 807 dbus_message_unref(pMsgSessions); 808 pMsgSessions = NULL; 1013 vboxService_dbus_message_discard(&pReplySessions); 809 1014 } 810 1015 } … … 821 1026 } 822 1027 823 if (pMsgSessions) 824 dbus_message_unref(pMsgSessions); 1028 vboxService_dbus_message_discard(&pMsgSessions); 825 1029 } 826 1030 else … … 840 1044 # endif /* RT_OS_LINUX */ 841 1045 # endif /* VBOX_WITH_DBUS */ 842 843 /** @todo Fedora/others: Handle systemd-loginctl. */844 1046 845 1047 /* Calc the string length. */
Note:
See TracChangeset
for help on using the changeset viewer.