Header And Logo

PostgreSQL
| The world's most advanced open source database.

security.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * security.c
00004  *    Microsoft Windows Win32 Security Support Functions
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  *
00008  * IDENTIFICATION
00009  *    src/backend/port/win32/security.c
00010  *
00011  *-------------------------------------------------------------------------
00012  */
00013 
00014 #include "postgres.h"
00015 
00016 
00017 static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token,
00018                             TOKEN_INFORMATION_CLASS class, char **InfoBuffer,
00019                               char *errbuf, int errsize);
00020 
00021 /*
00022  * Returns nonzero if the current user has administrative privileges,
00023  * or zero if not.
00024  *
00025  * Note: this cannot use ereport() because it's called too early during
00026  * startup.
00027  */
00028 int
00029 pgwin32_is_admin(void)
00030 {
00031     HANDLE      AccessToken;
00032     char       *InfoBuffer = NULL;
00033     char        errbuf[256];
00034     PTOKEN_GROUPS Groups;
00035     PSID        AdministratorsSid;
00036     PSID        PowerUsersSid;
00037     SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
00038     UINT        x;
00039     BOOL        success;
00040 
00041     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
00042     {
00043         write_stderr("could not open process token: error code %lu\n",
00044                      GetLastError());
00045         exit(1);
00046     }
00047 
00048     if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
00049                                        &InfoBuffer, errbuf, sizeof(errbuf)))
00050     {
00051         write_stderr("%s", errbuf);
00052         exit(1);
00053     }
00054 
00055     Groups = (PTOKEN_GROUPS) InfoBuffer;
00056 
00057     CloseHandle(AccessToken);
00058 
00059     if (!AllocateAndInitializeSid(&NtAuthority, 2,
00060          SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
00061                                   0, &AdministratorsSid))
00062     {
00063         write_stderr("could not get SID for Administrators group: error code %lu\n",
00064                      GetLastError());
00065         exit(1);
00066     }
00067 
00068     if (!AllocateAndInitializeSid(&NtAuthority, 2,
00069     SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
00070                                   0, &PowerUsersSid))
00071     {
00072         write_stderr("could not get SID for PowerUsers group: error code %lu\n",
00073                      GetLastError());
00074         exit(1);
00075     }
00076 
00077     success = FALSE;
00078 
00079     for (x = 0; x < Groups->GroupCount; x++)
00080     {
00081         if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
00082             (EqualSid(PowerUsersSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
00083         {
00084             success = TRUE;
00085             break;
00086         }
00087     }
00088 
00089     free(InfoBuffer);
00090     FreeSid(AdministratorsSid);
00091     FreeSid(PowerUsersSid);
00092     return success;
00093 }
00094 
00095 /*
00096  * We consider ourselves running as a service if one of the following is
00097  * true:
00098  *
00099  * 1) We are running as Local System (only used by services)
00100  * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
00101  *    process token by the SCM when starting a service)
00102  *
00103  * Return values:
00104  *   0 = Not service
00105  *   1 = Service
00106  *  -1 = Error
00107  *
00108  * Note: we can't report errors via either ereport (we're called too early)
00109  * or write_stderr (because that calls this).  We are therefore reduced to
00110  * writing directly on stderr, which sucks, but we have few alternatives.
00111  */
00112 int
00113 pgwin32_is_service(void)
00114 {
00115     static int  _is_service = -1;
00116     HANDLE      AccessToken;
00117     char       *InfoBuffer = NULL;
00118     char        errbuf[256];
00119     PTOKEN_GROUPS Groups;
00120     PTOKEN_USER User;
00121     PSID        ServiceSid;
00122     PSID        LocalSystemSid;
00123     SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
00124     UINT        x;
00125 
00126     /* Only check the first time */
00127     if (_is_service != -1)
00128         return _is_service;
00129 
00130     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
00131     {
00132         fprintf(stderr, "could not open process token: error code %lu\n",
00133                 GetLastError());
00134         return -1;
00135     }
00136 
00137     /* First check for local system */
00138     if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenUser, &InfoBuffer,
00139                                        errbuf, sizeof(errbuf)))
00140     {
00141         fprintf(stderr, "%s", errbuf);
00142         return -1;
00143     }
00144 
00145     User = (PTOKEN_USER) InfoBuffer;
00146 
00147     if (!AllocateAndInitializeSid(&NtAuthority, 1,
00148                               SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
00149                                   &LocalSystemSid))
00150     {
00151         fprintf(stderr, "could not get SID for local system account\n");
00152         CloseHandle(AccessToken);
00153         return -1;
00154     }
00155 
00156     if (EqualSid(LocalSystemSid, User->User.Sid))
00157     {
00158         FreeSid(LocalSystemSid);
00159         free(InfoBuffer);
00160         CloseHandle(AccessToken);
00161         _is_service = 1;
00162         return _is_service;
00163     }
00164 
00165     FreeSid(LocalSystemSid);
00166     free(InfoBuffer);
00167 
00168     /* Now check for group SID */
00169     if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer,
00170                                        errbuf, sizeof(errbuf)))
00171     {
00172         fprintf(stderr, "%s", errbuf);
00173         return -1;
00174     }
00175 
00176     Groups = (PTOKEN_GROUPS) InfoBuffer;
00177 
00178     if (!AllocateAndInitializeSid(&NtAuthority, 1,
00179                                   SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
00180                                   &ServiceSid))
00181     {
00182         fprintf(stderr, "could not get SID for service group\n");
00183         free(InfoBuffer);
00184         CloseHandle(AccessToken);
00185         return -1;
00186     }
00187 
00188     _is_service = 0;
00189     for (x = 0; x < Groups->GroupCount; x++)
00190     {
00191         if (EqualSid(ServiceSid, Groups->Groups[x].Sid))
00192         {
00193             _is_service = 1;
00194             break;
00195         }
00196     }
00197 
00198     free(InfoBuffer);
00199     FreeSid(ServiceSid);
00200 
00201     CloseHandle(AccessToken);
00202 
00203     return _is_service;
00204 }
00205 
00206 
00207 /*
00208  * Call GetTokenInformation() on a token and return a dynamically sized
00209  * buffer with the information in it. This buffer must be free():d by
00210  * the calling function!
00211  */
00212 static BOOL
00213 pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class,
00214                               char **InfoBuffer, char *errbuf, int errsize)
00215 {
00216     DWORD       InfoBufferSize;
00217 
00218     if (GetTokenInformation(token, class, NULL, 0, &InfoBufferSize))
00219     {
00220         snprintf(errbuf, errsize, "could not get token information: got zero size\n");
00221         return FALSE;
00222     }
00223 
00224     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
00225     {
00226         snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
00227                  GetLastError());
00228         return FALSE;
00229     }
00230 
00231     *InfoBuffer = malloc(InfoBufferSize);
00232     if (*InfoBuffer == NULL)
00233     {
00234         snprintf(errbuf, errsize, "could not allocate %d bytes for token information\n",
00235                  (int) InfoBufferSize);
00236         return FALSE;
00237     }
00238 
00239     if (!GetTokenInformation(token, class, *InfoBuffer,
00240                              InfoBufferSize, &InfoBufferSize))
00241     {
00242         snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
00243                  GetLastError());
00244         return FALSE;
00245     }
00246 
00247     return TRUE;
00248 }