Skip to content

Commit b15f9b0

Browse files
committed
Replace direct fprintf(stderr) calls by write_stderr(), and cause this
routine to do something appropriate on Win32. Also, add a security check on Win32 that parallels the can't-run-as-root check on Unix. Magnus Hagander
1 parent b5b9e33 commit b15f9b0

File tree

13 files changed

+319
-102
lines changed

13 files changed

+319
-102
lines changed

src/backend/bootstrap/bootstrap.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.184 2004/06/06 00:41:26 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.185 2004/06/24 21:02:24 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -328,12 +328,11 @@ BootstrapMain(int argc, char *argv[])
328328
{
329329
if (!potential_DataDir)
330330
{
331-
fprintf(stderr,
332-
gettext("%s does not know where to find the database system data.\n"
333-
"You must specify the directory that contains the database system\n"
334-
"either by specifying the -D invocation option or by setting the\n"
335-
"PGDATA environment variable.\n"),
336-
argv[0]);
331+
write_stderr("%s does not know where to find the database system data.\n"
332+
"You must specify the directory that contains the database system\n"
333+
"either by specifying the -D invocation option or by setting the\n"
334+
"PGDATA environment variable.\n",
335+
argv[0]);
337336
proc_exit(1);
338337
}
339338
SetDataDir(potential_DataDir);
@@ -503,15 +502,14 @@ BootstrapMain(int argc, char *argv[])
503502
static void
504503
usage(void)
505504
{
506-
fprintf(stderr,
507-
gettext("Usage:\n"
505+
write_stderr("Usage:\n"
508506
" postgres -boot [OPTION]... DBNAME\n"
509507
" -c NAME=VALUE set run-time parameter\n"
510508
" -d 1-5 debug level\n"
511509
" -D datadir data directory\n"
512510
" -F turn off fsync\n"
513511
" -o file send debug output to file\n"
514-
" -x num internal use\n"));
512+
" -x num internal use\n");
515513

516514
proc_exit(1);
517515
}

src/backend/main/main.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/main/main.c,v 1.86 2004/06/03 00:07:36 momjian Exp $
16+
* $PostgreSQL: pgsql/src/backend/main/main.c,v 1.87 2004/06/24 21:02:33 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -91,8 +91,8 @@ main(int argc, char *argv[])
9191
#if defined(__alpha) /* no __alpha__ ? */
9292
if (setsysinfo(SSI_NVPAIRS, buffer, 1, (caddr_t) NULL,
9393
(unsigned long) NULL) < 0)
94-
fprintf(stderr, gettext("%s: setsysinfo failed: %s\n"),
95-
argv[0], strerror(errno));
94+
write_stderr("%s: setsysinfo failed: %s\n",
95+
argv[0], strerror(errno));
9696
#endif
9797
#endif /* NOFIXADE || NOPRINTADE */
9898

@@ -109,7 +109,7 @@ main(int argc, char *argv[])
109109
err = WSAStartup(MAKEWORD(2, 2), &wsaData);
110110
if (err != 0)
111111
{
112-
fprintf(stderr, "%s: WSAStartup failed: %d\n",
112+
write_stderr("%s: WSAStartup failed: %d\n",
113113
argv[0], err);
114114
exit(1);
115115
}
@@ -212,12 +212,10 @@ main(int argc, char *argv[])
212212
*/
213213
if (geteuid() == 0)
214214
{
215-
fprintf(stderr,
216-
gettext("\"root\" execution of the PostgreSQL server is not permitted.\n"
217-
"The server must be started under an unprivileged user ID to prevent\n"
218-
"possible system security compromise. See the documentation for\n"
219-
"more information on how to properly start the server.\n"
220-
));
215+
write_stderr("\"root\" execution of the PostgreSQL server is not permitted.\n"
216+
"The server must be started under an unprivileged user ID to prevent\n"
217+
"possible system security compromise. See the documentation for\n"
218+
"more information on how to properly start the server.\n");
221219
exit(1);
222220
}
223221
#endif /* !__BEOS__ */
@@ -233,9 +231,17 @@ main(int argc, char *argv[])
233231
*/
234232
if (getuid() != geteuid())
235233
{
236-
fprintf(stderr,
237-
gettext("%s: real and effective user IDs must match\n"),
238-
argv[0]);
234+
write_stderr("%s: real and effective user IDs must match\n",
235+
argv[0]);
236+
exit(1);
237+
}
238+
#else /* WIN32 */
239+
if (pgwin32_is_admin())
240+
{
241+
write_stderr("execution of PostgreSQL by a user with administrative permissions is not permitted.\n"
242+
"The server must be started under an unprivileged user ID to prevent\n"
243+
"possible system security compromise. See the documentation for\n"
244+
"more information on how to properly start the server.\n");
239245
exit(1);
240246
}
241247
#endif /* !WIN32 */
@@ -292,8 +298,8 @@ main(int argc, char *argv[])
292298
pw = getpwuid(geteuid());
293299
if (pw == NULL)
294300
{
295-
fprintf(stderr, gettext("%s: invalid effective UID: %d\n"),
296-
argv[0], (int) geteuid());
301+
write_stderr("%s: invalid effective UID: %d\n",
302+
argv[0], (int) geteuid());
297303
exit(1);
298304
}
299305
/* Allocate new memory because later getpwuid() calls can overwrite it */
@@ -305,7 +311,7 @@ main(int argc, char *argv[])
305311
pw_name_persist = malloc(namesize);
306312
if (!GetUserName(pw_name_persist, &namesize))
307313
{
308-
fprintf(stderr, gettext("%s: could not determine user name (GetUserName failed)\n"),
314+
write_stderr("%s: could not determine user name (GetUserName failed)\n",
309315
argv[0]);
310316
exit(1);
311317
}

src/backend/nls.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.12 2004/06/10 17:10:24 petere Exp $
1+
# $PostgreSQL: pgsql/src/backend/nls.mk,v 1.13 2004/06/24 21:02:40 tgl Exp $
22
CATALOG_NAME := postgres
33
AVAIL_LANGUAGES := af cs de es hr hu it nb pt_BR ru sv tr zh_CN zh_TW
44
GETTEXT_FILES := + gettext-files
55
# you can add "elog:2" and "errmsg_internal" to this list if you want to
66
# include internal messages in the translation list.
7-
GETTEXT_TRIGGERS:= errmsg errdetail errhint errcontext postmaster_error yyerror
7+
GETTEXT_TRIGGERS:= errmsg errdetail errhint errcontext write_stderr yyerror
88

99
gettext-files: distprep
1010
find $(srcdir)/ -name '*.c' -print >$@

src/backend/port/win32/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
# Makefile for port/win32
55
#
66
# IDENTIFICATION
7-
# $PostgreSQL: pgsql/src/backend/port/win32/Makefile,v 1.4 2004/04/12 16:19:18 momjian Exp $
7+
# $PostgreSQL: pgsql/src/backend/port/win32/Makefile,v 1.5 2004/06/24 21:02:42 tgl Exp $
88
#
99
#-------------------------------------------------------------------------
1010

1111
subdir = src/backend/port/win32
1212
top_builddir = ../../../..
1313
include $(top_builddir)/src/Makefile.global
1414

15-
OBJS = sema.o shmem.o timer.o socket.o signal.o
15+
OBJS = sema.o shmem.o timer.o socket.o signal.o security.o
1616

1717
all: SUBSYS.o
1818

src/backend/port/win32/security.c

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* security.c
4+
* Microsoft Windows Win32 Security Support Functions
5+
*
6+
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7+
*
8+
* IDENTIFICATION
9+
* $PostgreSQL: pgsql/src/backend/port/win32/security.c,v 1.1 2004/06/24 21:02:42 tgl Exp $
10+
*
11+
*-------------------------------------------------------------------------
12+
*/
13+
14+
#include "postgres.h"
15+
16+
17+
/*
18+
* Returns nonzero if the current user has administrative privileges,
19+
* or zero if not.
20+
*
21+
* Note: this cannot use ereport() because it's called too early during
22+
* startup.
23+
*/
24+
int
25+
pgwin32_is_admin(void)
26+
{
27+
HANDLE AccessToken;
28+
UCHAR InfoBuffer[1024];
29+
PTOKEN_GROUPS Groups = (PTOKEN_GROUPS)InfoBuffer;
30+
DWORD InfoBufferSize;
31+
PSID AdministratorsSid;
32+
PSID PowerUsersSid;
33+
SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY };
34+
UINT x;
35+
BOOL success;
36+
37+
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_READ,&AccessToken))
38+
{
39+
write_stderr("failed to open process token: %d\n",
40+
(int)GetLastError());
41+
exit(1);
42+
}
43+
44+
if (!GetTokenInformation(AccessToken,TokenGroups,InfoBuffer,
45+
1024, &InfoBufferSize))
46+
{
47+
write_stderr("failed to get token information: %d\n",
48+
(int)GetLastError());
49+
exit(1);
50+
}
51+
52+
CloseHandle(AccessToken);
53+
54+
if(!AllocateAndInitializeSid(&NtAuthority, 2,
55+
SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
56+
0,&AdministratorsSid))
57+
{
58+
write_stderr("failed to get SID for Administrators group: %d\n",
59+
(int)GetLastError());
60+
exit(1);
61+
}
62+
63+
if (!AllocateAndInitializeSid(&NtAuthority, 2,
64+
SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
65+
0, &PowerUsersSid))
66+
{
67+
write_stderr("failed to get SID for PowerUsers group: %d\n",
68+
(int)GetLastError());
69+
exit(1);
70+
}
71+
72+
success = FALSE;
73+
74+
for (x=0; x<Groups->GroupCount; x++)
75+
{
76+
if (EqualSid(AdministratorsSid, Groups->Groups[x].Sid) ||
77+
EqualSid(PowerUsersSid, Groups->Groups[x].Sid))
78+
{
79+
success = TRUE;
80+
break;
81+
}
82+
}
83+
84+
FreeSid(AdministratorsSid);
85+
FreeSid(PowerUsersSid);
86+
return success;
87+
}
88+
89+
/*
90+
* We consider ourselves running as a service if one of the following is
91+
* true:
92+
*
93+
* 1) We are running as Local System (only used by services)
94+
* 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
95+
* process token by the SCM when starting a service)
96+
*
97+
* Return values:
98+
* 0 = Not service
99+
* 1 = Service
100+
* -1 = Error
101+
*
102+
* Note: we can't report errors via either ereport (we're called too early)
103+
* or write_stderr (because that calls this). We are therefore reduced to
104+
* writing directly on stderr, which sucks, but we have few alternatives.
105+
*/
106+
int
107+
pgwin32_is_service(void)
108+
{
109+
static int _is_service = -1;
110+
HANDLE AccessToken;
111+
UCHAR InfoBuffer[1024];
112+
PTOKEN_GROUPS Groups = (PTOKEN_GROUPS)InfoBuffer;
113+
PTOKEN_USER User = (PTOKEN_USER)InfoBuffer;
114+
DWORD InfoBufferSize;
115+
PSID ServiceSid;
116+
PSID LocalSystemSid;
117+
SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY };
118+
UINT x;
119+
120+
/* Only check the first time */
121+
if (_is_service != -1)
122+
return _is_service;
123+
124+
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_READ,&AccessToken)) {
125+
fprintf(stderr,"failed to open process token: %d\n",
126+
(int)GetLastError());
127+
return -1;
128+
}
129+
130+
/* First check for local system */
131+
if (!GetTokenInformation(AccessToken,TokenUser,InfoBuffer,1024,&InfoBufferSize)) {
132+
fprintf(stderr,"failed to get token information: %d\n",
133+
(int)GetLastError());
134+
return -1;
135+
}
136+
137+
if (!AllocateAndInitializeSid(&NtAuthority,1,
138+
SECURITY_LOCAL_SYSTEM_RID,0,0,0,0,0,0,0,
139+
&LocalSystemSid)) {
140+
fprintf(stderr,"failed to get SID for local system account\n");
141+
CloseHandle(AccessToken);
142+
return -1;
143+
}
144+
145+
if (EqualSid(LocalSystemSid, User->User.Sid)) {
146+
FreeSid(LocalSystemSid);
147+
CloseHandle(AccessToken);
148+
_is_service = 1;
149+
return _is_service;
150+
}
151+
152+
FreeSid(LocalSystemSid);
153+
154+
/* Now check for group SID */
155+
if (!GetTokenInformation(AccessToken,TokenGroups,InfoBuffer,1024,&InfoBufferSize)) {
156+
fprintf(stderr,"failed to get token information: %d\n",
157+
(int)GetLastError());
158+
return -1;
159+
}
160+
161+
if (!AllocateAndInitializeSid(&NtAuthority,1,
162+
SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
163+
&ServiceSid)) {
164+
fprintf(stderr,"failed to get SID for service group\n");
165+
CloseHandle(AccessToken);
166+
return -1;
167+
}
168+
169+
_is_service = 0;
170+
for (x = 0; x < Groups->GroupCount; x++)
171+
{
172+
if (EqualSid(ServiceSid, Groups->Groups[x].Sid))
173+
{
174+
_is_service = 1;
175+
break;
176+
}
177+
}
178+
179+
FreeSid(ServiceSid);
180+
181+
CloseHandle(AccessToken);
182+
183+
return _is_service;
184+
}

0 commit comments

Comments
 (0)