|
9 | 9 | *
|
10 | 10 | *
|
11 | 11 | * IDENTIFICATION
|
12 |
| - * $PostgreSQL: pgsql/src/port/exec.c,v 1.57 2008/01/01 19:46:00 momjian Exp $ |
| 12 | + * $PostgreSQL: pgsql/src/port/exec.c,v 1.58 2008/02/29 15:31:33 mha Exp $ |
13 | 13 | *
|
14 | 14 | *-------------------------------------------------------------------------
|
15 | 15 | */
|
@@ -55,6 +55,9 @@ static int validate_exec(const char *path);
|
55 | 55 | static int resolve_symlinks(char *path);
|
56 | 56 | static char *pipe_read_line(char *cmd, char *line, int maxsize);
|
57 | 57 |
|
| 58 | +#ifdef WIN32 |
| 59 | +static BOOL GetUserSid(PSID * ppSidUser, HANDLE hToken); |
| 60 | +#endif |
58 | 61 |
|
59 | 62 | /*
|
60 | 63 | * validate_exec -- validate "path" as an executable file
|
@@ -657,3 +660,217 @@ set_pglocale_pgservice(const char *argv0, const char *app)
|
657 | 660 | putenv(strdup(env_path));
|
658 | 661 | }
|
659 | 662 | }
|
| 663 | + |
| 664 | +#ifdef WIN32 |
| 665 | + |
| 666 | +/* |
| 667 | + * AddUserToDacl(HANDLE hProcess) |
| 668 | + * |
| 669 | + * This function adds the current user account to the default DACL |
| 670 | + * which gets attached to the restricted token used when we create |
| 671 | + * a restricted process. |
| 672 | + * |
| 673 | + * This is required because of some security changes in Windows |
| 674 | + * that appeared in patches to XP/2K3 and in Vista/2008. |
| 675 | + * |
| 676 | + * On these machines, the Administrator account is not included in |
| 677 | + * the default DACL - you just get Administrators + System. For |
| 678 | + * regular users you get User + System. Because we strip Administrators |
| 679 | + * when we create the restricted token, we are left with only System |
| 680 | + * in the DACL which leads to access denied errors for later CreatePipe() |
| 681 | + * and CreateProcess() calls when running as Administrator. |
| 682 | + * |
| 683 | + * This function fixes this problem by modifying the DACL of the |
| 684 | + * specified process and explicitly re-adding the current user account. |
| 685 | + * This is still secure because the Administrator account inherits it's |
| 686 | + * privileges from the Administrators group - it doesn't have any of |
| 687 | + * it's own. |
| 688 | + */ |
| 689 | +BOOL |
| 690 | +AddUserToDacl(HANDLE hProcess) |
| 691 | +{ |
| 692 | + int i; |
| 693 | + ACL_SIZE_INFORMATION asi; |
| 694 | + ACCESS_ALLOWED_ACE *pace; |
| 695 | + DWORD dwNewAclSize; |
| 696 | + DWORD dwSize = 0; |
| 697 | + DWORD dwTokenInfoLength = 0; |
| 698 | + DWORD dwResult = 0; |
| 699 | + HANDLE hToken = NULL; |
| 700 | + PACL pacl = NULL; |
| 701 | + PSID psidUser = NULL; |
| 702 | + TOKEN_DEFAULT_DACL tddNew; |
| 703 | + TOKEN_DEFAULT_DACL *ptdd = NULL; |
| 704 | + TOKEN_INFORMATION_CLASS tic = TokenDefaultDacl; |
| 705 | + BOOL ret = FALSE; |
| 706 | + |
| 707 | + /* Get the token for the process */ |
| 708 | + if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &hToken)) |
| 709 | + { |
| 710 | + log_error("could not open process token: %ui", GetLastError()); |
| 711 | + goto cleanup; |
| 712 | + } |
| 713 | + |
| 714 | + /* Figure out the buffer size for the DACL info */ |
| 715 | + if (!GetTokenInformation(hToken, tic, (LPVOID) NULL, dwTokenInfoLength, &dwSize)) |
| 716 | + { |
| 717 | + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) |
| 718 | + { |
| 719 | + ptdd = (TOKEN_DEFAULT_DACL *) LocalAlloc(LPTR, dwSize); |
| 720 | + if (ptdd == NULL) |
| 721 | + { |
| 722 | + log_error("could not allocate %i bytes of memory", dwSize); |
| 723 | + goto cleanup; |
| 724 | + } |
| 725 | + |
| 726 | + if (!GetTokenInformation(hToken, tic, (LPVOID) ptdd, dwSize, &dwSize)) |
| 727 | + { |
| 728 | + log_error("could not get token information: %ui", GetLastError()); |
| 729 | + goto cleanup; |
| 730 | + } |
| 731 | + } |
| 732 | + else |
| 733 | + { |
| 734 | + log_error("could not get token information buffer size: %ui", GetLastError()); |
| 735 | + goto cleanup; |
| 736 | + } |
| 737 | + } |
| 738 | + |
| 739 | + /* Get the ACL info */ |
| 740 | + if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID) & asi, |
| 741 | + (DWORD) sizeof(ACL_SIZE_INFORMATION), |
| 742 | + AclSizeInformation)) |
| 743 | + { |
| 744 | + log_error("could not get ACL information: %ui", GetLastError()); |
| 745 | + goto cleanup; |
| 746 | + } |
| 747 | + |
| 748 | + /* Get the SID for the current user. We need to add this to the ACL. */ |
| 749 | + if (!GetUserSid(&psidUser, hToken)) |
| 750 | + { |
| 751 | + log_error("could not get user SID: %ui", GetLastError()); |
| 752 | + goto cleanup; |
| 753 | + } |
| 754 | + |
| 755 | + /* Figure out the size of the new ACL */ |
| 756 | + dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidUser) - sizeof(DWORD); |
| 757 | + |
| 758 | + /* Allocate the ACL buffer & initialize it */ |
| 759 | + pacl = (PACL) LocalAlloc(LPTR, dwNewAclSize); |
| 760 | + if (pacl == NULL) |
| 761 | + { |
| 762 | + log_error("could not allocate %i bytes of memory", dwNewAclSize); |
| 763 | + goto cleanup; |
| 764 | + } |
| 765 | + |
| 766 | + if (!InitializeAcl(pacl, dwNewAclSize, ACL_REVISION)) |
| 767 | + { |
| 768 | + log_error("could not initialize ACL: %ui", GetLastError()); |
| 769 | + goto cleanup; |
| 770 | + } |
| 771 | + |
| 772 | + /* Loop through the existing ACEs, and build the new ACL */ |
| 773 | + for (i = 0; i < (int) asi.AceCount; i++) |
| 774 | + { |
| 775 | + if (!GetAce(ptdd->DefaultDacl, i, (LPVOID *) & pace)) |
| 776 | + { |
| 777 | + log_error("could not get ACE: %ui", GetLastError()); |
| 778 | + goto cleanup; |
| 779 | + } |
| 780 | + |
| 781 | + if (!AddAce(pacl, ACL_REVISION, MAXDWORD, pace, ((PACE_HEADER) pace)->AceSize)) |
| 782 | + { |
| 783 | + log_error("could not add ACE: %ui", GetLastError()); |
| 784 | + goto cleanup; |
| 785 | + } |
| 786 | + } |
| 787 | + |
| 788 | + /* Add the new ACE for the current user */ |
| 789 | + if (!AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psidUser)) |
| 790 | + { |
| 791 | + log_error("could not add access allowed ACE: %ui", GetLastError()); |
| 792 | + goto cleanup; |
| 793 | + } |
| 794 | + |
| 795 | + /* Set the new DACL in the token */ |
| 796 | + tddNew.DefaultDacl = pacl; |
| 797 | + |
| 798 | + if (!SetTokenInformation(hToken, tic, (LPVOID) & tddNew, dwNewAclSize)) |
| 799 | + { |
| 800 | + log_error("could not set token information: %ui", GetLastError()); |
| 801 | + goto cleanup; |
| 802 | + } |
| 803 | + |
| 804 | + ret = TRUE; |
| 805 | + |
| 806 | +cleanup: |
| 807 | + if (psidUser) |
| 808 | + FreeSid(psidUser); |
| 809 | + |
| 810 | + if (pacl) |
| 811 | + LocalFree((HLOCAL) pacl); |
| 812 | + |
| 813 | + if (ptdd) |
| 814 | + LocalFree((HLOCAL) ptdd); |
| 815 | + |
| 816 | + if (hToken) |
| 817 | + CloseHandle(hToken); |
| 818 | + |
| 819 | + return ret; |
| 820 | +} |
| 821 | + |
| 822 | +/* |
| 823 | + * GetUserSid*PSID *ppSidUser, HANDLE hToken) |
| 824 | + * |
| 825 | + * Get the SID for the current user |
| 826 | + */ |
| 827 | +static BOOL |
| 828 | +GetUserSid(PSID * ppSidUser, HANDLE hToken) |
| 829 | +{ |
| 830 | + DWORD dwLength; |
| 831 | + DWORD cbName = 250; |
| 832 | + DWORD cbDomainName = 250; |
| 833 | + PTOKEN_USER pTokenUser = NULL; |
| 834 | + |
| 835 | + |
| 836 | + if (!GetTokenInformation(hToken, |
| 837 | + TokenUser, |
| 838 | + pTokenUser, |
| 839 | + 0, |
| 840 | + &dwLength)) |
| 841 | + { |
| 842 | + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) |
| 843 | + { |
| 844 | + pTokenUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); |
| 845 | + |
| 846 | + if (pTokenUser == NULL) |
| 847 | + { |
| 848 | + log_error("could not allocate %ui bytes of memory", dwLength); |
| 849 | + return FALSE; |
| 850 | + } |
| 851 | + } |
| 852 | + else |
| 853 | + { |
| 854 | + log_error("could not get token information buffer size: %ui", GetLastError()); |
| 855 | + return FALSE; |
| 856 | + } |
| 857 | + } |
| 858 | + |
| 859 | + if (!GetTokenInformation(hToken, |
| 860 | + TokenUser, |
| 861 | + pTokenUser, |
| 862 | + dwLength, |
| 863 | + &dwLength)) |
| 864 | + { |
| 865 | + HeapFree(GetProcessHeap(), 0, pTokenUser); |
| 866 | + pTokenUser = NULL; |
| 867 | + |
| 868 | + log_error("could not get token information: %ui", GetLastError()); |
| 869 | + return FALSE; |
| 870 | + } |
| 871 | + |
| 872 | + *ppSidUser = pTokenUser->User.Sid; |
| 873 | + return TRUE; |
| 874 | +} |
| 875 | + |
| 876 | +#endif |
0 commit comments