|
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 intvalidate_exec(const char *path);
|
55 | 55 | staticintresolve_symlinks(char*path);
|
56 | 56 | staticchar*pipe_read_line(char*cmd,char*line,intmaxsize);
|
57 | 57 |
|
| 58 | +#ifdefWIN32 |
| 59 | +staticBOOLGetUserSid(PSID*ppSidUser,HANDLEhToken); |
| 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 | +#ifdefWIN32 |
| 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(HANDLEhProcess) |
| 691 | +{ |
| 692 | +inti; |
| 693 | +ACL_SIZE_INFORMATIONasi; |
| 694 | +ACCESS_ALLOWED_ACE*pace; |
| 695 | +DWORDdwNewAclSize; |
| 696 | +DWORDdwSize=0; |
| 697 | +DWORDdwTokenInfoLength=0; |
| 698 | +DWORDdwResult=0; |
| 699 | +HANDLEhToken=NULL; |
| 700 | +PACLpacl=NULL; |
| 701 | +PSIDpsidUser=NULL; |
| 702 | +TOKEN_DEFAULT_DACLtddNew; |
| 703 | +TOKEN_DEFAULT_DACL*ptdd=NULL; |
| 704 | +TOKEN_INFORMATION_CLASStic=TokenDefaultDacl; |
| 705 | +BOOLret= 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 | +gotocleanup; |
| 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 | +gotocleanup; |
| 724 | +} |
| 725 | + |
| 726 | +if (!GetTokenInformation(hToken,tic, (LPVOID)ptdd,dwSize,&dwSize)) |
| 727 | +{ |
| 728 | +log_error("could not get token information: %ui",GetLastError()); |
| 729 | +gotocleanup; |
| 730 | +} |
| 731 | +} |
| 732 | +else |
| 733 | +{ |
| 734 | +log_error("could not get token information buffer size: %ui",GetLastError()); |
| 735 | +gotocleanup; |
| 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 | +gotocleanup; |
| 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 | +gotocleanup; |
| 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 | +gotocleanup; |
| 764 | +} |
| 765 | + |
| 766 | +if (!InitializeAcl(pacl,dwNewAclSize,ACL_REVISION)) |
| 767 | +{ |
| 768 | +log_error("could not initialize ACL: %ui",GetLastError()); |
| 769 | +gotocleanup; |
| 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 | +gotocleanup; |
| 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 | +gotocleanup; |
| 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 | +gotocleanup; |
| 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 | +gotocleanup; |
| 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 | +returnret; |
| 820 | +} |
| 821 | + |
| 822 | +/* |
| 823 | + * GetUserSid*PSID *ppSidUser, HANDLE hToken) |
| 824 | + * |
| 825 | + * Get the SID for the current user |
| 826 | + */ |
| 827 | +staticBOOL |
| 828 | +GetUserSid(PSID*ppSidUser,HANDLEhToken) |
| 829 | +{ |
| 830 | +DWORDdwLength; |
| 831 | +DWORDcbName=250; |
| 832 | +DWORDcbDomainName=250; |
| 833 | +PTOKEN_USERpTokenUser=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 |