]>
Commit | Line | Data |
---|---|---|
c0d1968a CV |
1 | /* sec_helper.cc: NT security helper functions |
2 | ||
b31c68c4 | 3 | Copyright 2000, 2001, 2002 Red Hat, Inc. |
c0d1968a CV |
4 | |
5 | Written by Corinna Vinschen <corinna@vinschen.de> | |
6 | ||
7 | This file is part of Cygwin. | |
8 | ||
9 | This software is a copyrighted work licensed under the terms of the | |
10 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
11 | details. */ | |
12 | ||
13 | #include "winsup.h" | |
14 | #include <grp.h> | |
15 | #include <pwd.h> | |
16 | #include <unistd.h> | |
17 | #include <stdlib.h> | |
c0d1968a CV |
18 | #include <limits.h> |
19 | #include <sys/types.h> | |
20 | #include <sys/stat.h> | |
21 | #include <sys/acl.h> | |
22 | #include <ctype.h> | |
23 | #include <wingdi.h> | |
24 | #include <winuser.h> | |
17db1105 | 25 | #include <wininet.h> |
c0d1968a | 26 | #include "cygerrno.h" |
6b91b8d5 | 27 | #include "security.h" |
c0d1968a CV |
28 | #include "fhandler.h" |
29 | #include "path.h" | |
30 | #include "dtable.h" | |
c0d1968a CV |
31 | #include "pinfo.h" |
32 | #include "cygheap.h" | |
d6ffc075 | 33 | #include "pwdgrp.h" |
c0d1968a | 34 | |
73d97618 CV |
35 | /* General purpose security attribute objects for global use. */ |
36 | SECURITY_ATTRIBUTES NO_COPY sec_none; | |
37 | SECURITY_ATTRIBUTES NO_COPY sec_none_nih; | |
38 | SECURITY_ATTRIBUTES NO_COPY sec_all; | |
39 | SECURITY_ATTRIBUTES NO_COPY sec_all_nih; | |
40 | ||
4a21c2d5 | 41 | SID_IDENTIFIER_AUTHORITY NO_COPY sid_auth[] = { |
1ff9f4b9 CF |
42 | {SECURITY_NULL_SID_AUTHORITY}, |
43 | {SECURITY_WORLD_SID_AUTHORITY}, | |
44 | {SECURITY_LOCAL_SID_AUTHORITY}, | |
45 | {SECURITY_CREATOR_SID_AUTHORITY}, | |
46 | {SECURITY_NON_UNIQUE_AUTHORITY}, | |
47 | {SECURITY_NT_AUTHORITY} | |
c0d1968a CV |
48 | }; |
49 | ||
85ecb9be CV |
50 | cygsid well_known_null_sid; |
51 | cygsid well_known_world_sid; | |
52 | cygsid well_known_local_sid; | |
53 | cygsid well_known_creator_owner_sid; | |
54 | cygsid well_known_creator_group_sid; | |
55 | cygsid well_known_dialup_sid; | |
56 | cygsid well_known_network_sid; | |
57 | cygsid well_known_batch_sid; | |
58 | cygsid well_known_interactive_sid; | |
59 | cygsid well_known_service_sid; | |
60 | cygsid well_known_authenticated_users_sid; | |
61 | cygsid well_known_system_sid; | |
62 | cygsid well_known_admins_sid; | |
63 | ||
4a21c2d5 CV |
64 | bool |
65 | cygpsid::operator== (const char *nsidstr) const | |
66 | { | |
67 | cygsid nsid (nsidstr); | |
68 | return psid == nsid; | |
69 | } | |
70 | ||
71 | __uid32_t | |
72 | cygpsid::get_id (BOOL search_grp, int *type) | |
73 | { | |
74 | /* First try to get SID from group, then passwd */ | |
75 | __uid32_t id = ILLEGAL_UID; | |
76 | ||
77 | if (search_grp) | |
78 | { | |
79 | struct __group32 *gr; | |
80 | if (cygheap->user.groups.pgsid == psid) | |
81 | id = myself->gid; | |
82 | else if ((gr = internal_getgrsid (*this))) | |
83 | id = gr->gr_gid; | |
84 | if (id != ILLEGAL_UID) | |
a113a3c5 | 85 | { |
4a21c2d5 CV |
86 | if (type) |
87 | *type = GROUP; | |
88 | return id; | |
89 | } | |
90 | } | |
91 | if (!search_grp || type) | |
92 | { | |
93 | struct passwd *pw; | |
94 | if (*this == cygheap->user.sid ()) | |
95 | id = myself->uid; | |
96 | else if ((pw = internal_getpwsid (*this))) | |
97 | id = pw->pw_uid; | |
98 | if (id != ILLEGAL_UID && type) | |
a113a3c5 | 99 | *type = USER; |
4a21c2d5 CV |
100 | } |
101 | return id; | |
102 | } | |
103 | ||
104 | ||
105 | char * | |
106 | cygpsid::string (char *nsidstr) const | |
107 | { | |
108 | char *t; | |
109 | DWORD i; | |
110 | ||
111 | if (!psid || !nsidstr) | |
112 | return NULL; | |
113 | strcpy (nsidstr, "S-1-"); | |
114 | t = nsidstr + sizeof ("S-1-") - 1; | |
115 | t += __small_sprintf (t, "%u", GetSidIdentifierAuthority (psid)->Value[5]); | |
116 | for (i = 0; i < *GetSidSubAuthorityCount (psid); ++i) | |
117 | t += __small_sprintf (t, "-%lu", *GetSidSubAuthority (psid, i)); | |
118 | return nsidstr; | |
119 | } | |
120 | ||
85ecb9be CV |
121 | void |
122 | cygsid::init () | |
123 | { | |
124 | well_known_null_sid = "S-1-0-0"; | |
125 | well_known_world_sid = "S-1-1-0"; | |
126 | well_known_local_sid = "S-1-2-0"; | |
127 | well_known_creator_owner_sid = "S-1-3-0"; | |
128 | well_known_creator_group_sid = "S-1-3-1"; | |
129 | well_known_dialup_sid = "S-1-5-1"; | |
130 | well_known_network_sid = "S-1-5-2"; | |
131 | well_known_batch_sid = "S-1-5-3"; | |
132 | well_known_interactive_sid = "S-1-5-4"; | |
133 | well_known_service_sid = "S-1-5-6"; | |
134 | well_known_authenticated_users_sid = "S-1-5-11"; | |
135 | well_known_system_sid = "S-1-5-18"; | |
136 | well_known_admins_sid = "S-1-5-32-544"; | |
137 | } | |
2b0a111f | 138 | |
c0d1968a | 139 | PSID |
2b0a111f | 140 | cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r) |
c0d1968a CV |
141 | { |
142 | DWORD i; | |
143 | ||
2b0a111f | 144 | if (s > 5 || cnt < 1 || cnt > 8) |
1fcc912f CV |
145 | { |
146 | psid = NO_SID; | |
147 | return NULL; | |
148 | } | |
2b0a111f | 149 | set (); |
c90e1cf1 | 150 | InitializeSid (psid, &sid_auth[s], cnt); |
c0d1968a CV |
151 | for (i = 0; i < cnt; ++i) |
152 | memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD)); | |
153 | return psid; | |
154 | } | |
155 | ||
2b0a111f CV |
156 | const PSID |
157 | cygsid::getfromstr (const char *nsidstr) | |
c0d1968a | 158 | { |
7a11fe60 CV |
159 | char *lasts; |
160 | DWORD s, cnt = 0; | |
161 | DWORD r[8]; | |
c0d1968a | 162 | |
7a11fe60 | 163 | if (nsidstr && !strncmp (nsidstr, "S-1-", 4)) |
1fcc912f | 164 | { |
7a11fe60 CV |
165 | s = strtoul (nsidstr + 4, &lasts, 10); |
166 | while ( cnt < 8 && *lasts == '-') | |
167 | r[cnt++] = strtoul (lasts + 1, &lasts, 10); | |
168 | if (!*lasts) | |
169 | return get_sid (s, cnt, r); | |
1fcc912f | 170 | } |
7a11fe60 | 171 | return psid = NO_SID; |
c0d1968a CV |
172 | } |
173 | ||
174 | BOOL | |
b2939a81 | 175 | cygsid::getfrompw (const struct passwd *pw) |
c0d1968a | 176 | { |
1fcc912f | 177 | char *sp = (pw && pw->pw_gecos) ? strrchr (pw->pw_gecos, ',') : NULL; |
647b92a7 | 178 | return (*this = sp ? sp + 1 : sp) != NULL; |
c0d1968a CV |
179 | } |
180 | ||
181 | BOOL | |
57196405 | 182 | cygsid::getfromgr (const struct __group32 *gr) |
c0d1968a | 183 | { |
1fcc912f | 184 | char *sp = (gr && gr->gr_passwd) ? gr->gr_passwd : NULL; |
647b92a7 | 185 | return (*this = sp) != NULL; |
c0d1968a CV |
186 | } |
187 | ||
0c8455c3 CV |
188 | bool |
189 | get_sids_info (cygpsid owner_sid, cygpsid group_sid, __uid32_t * uidret, __gid32_t * gidret) | |
190 | { | |
191 | struct passwd *pw; | |
192 | struct __group32 *gr = NULL; | |
193 | bool ret = false; | |
194 | ||
61a52599 CV |
195 | owner_sid.debug_print ("get_sids_info: owner SID ="); |
196 | group_sid.debug_print ("get_sids_info: group SID ="); | |
197 | ||
0c8455c3 CV |
198 | if (group_sid == cygheap->user.groups.pgsid) |
199 | *gidret = myself->gid; | |
200 | else if ((gr = internal_getgrsid (group_sid))) | |
201 | *gidret = gr->gr_gid; | |
202 | else | |
203 | *gidret = ILLEGAL_GID; | |
204 | ||
205 | if (owner_sid == cygheap->user.sid ()) | |
206 | { | |
207 | *uidret = myself->uid; | |
208 | if (*gidret == myself->gid) | |
209 | ret = true; | |
210 | else | |
211 | ret = (internal_getgroups (0, NULL, &group_sid) > 0); | |
212 | } | |
213 | else if ((pw = internal_getpwsid (owner_sid))) | |
214 | { | |
215 | *uidret = pw->pw_uid; | |
216 | if (gr || (*gidret != ILLEGAL_GID | |
217 | && (gr = internal_getgrgid (*gidret)))) | |
218 | for (int idx = 0; gr->gr_mem[idx]; ++idx) | |
219 | if ((ret = strcasematch (pw->pw_name, gr->gr_mem[idx]))) | |
220 | break; | |
221 | } | |
222 | else | |
223 | *uidret = ILLEGAL_UID; | |
224 | ||
225 | return ret; | |
226 | } | |
227 | ||
2e8abfc1 | 228 | #if 0 // unused |
17db1105 CV |
229 | #define SIDLEN (sidlen = MAX_SID_LEN, &sidlen) |
230 | #define DOMLEN (domlen = INTERNET_MAX_HOST_NAME_LENGTH, &domlen) | |
231 | ||
c0d1968a CV |
232 | BOOL |
233 | lookup_name (const char *name, const char *logsrv, PSID ret_sid) | |
234 | { | |
d551169a | 235 | cygsid sid; |
c0d1968a | 236 | DWORD sidlen; |
17db1105 CV |
237 | char domuser[INTERNET_MAX_HOST_NAME_LENGTH + UNLEN + 2]; |
238 | char dom[INTERNET_MAX_HOST_NAME_LENGTH + 1]; | |
c0d1968a CV |
239 | DWORD domlen; |
240 | SID_NAME_USE acc_type; | |
241 | ||
242 | debug_printf ("name : %s", name ? name : "NULL"); | |
243 | ||
244 | if (!name) | |
245 | return FALSE; | |
246 | ||
247 | if (cygheap->user.domain ()) | |
248 | { | |
249 | strcat (strcat (strcpy (domuser, cygheap->user.domain ()), "\\"), name); | |
17db1105 | 250 | if (LookupAccountName (NULL, domuser, sid, SIDLEN, dom, DOMLEN, &acc_type) |
c0d1968a CV |
251 | && legal_sid_type (acc_type)) |
252 | goto got_it; | |
253 | if (logsrv && *logsrv | |
17db1105 CV |
254 | && LookupAccountName (logsrv, domuser, sid, SIDLEN, |
255 | dom, DOMLEN, &acc_type) | |
c0d1968a CV |
256 | && legal_sid_type (acc_type)) |
257 | goto got_it; | |
258 | } | |
259 | if (logsrv && *logsrv) | |
260 | { | |
17db1105 | 261 | if (LookupAccountName (logsrv, name, sid, SIDLEN, dom, DOMLEN, &acc_type) |
c0d1968a CV |
262 | && legal_sid_type (acc_type)) |
263 | goto got_it; | |
264 | if (acc_type == SidTypeDomain) | |
265 | { | |
266 | strcat (strcat (strcpy (domuser, dom), "\\"), name); | |
17db1105 CV |
267 | if (LookupAccountName (logsrv, domuser, sid, SIDLEN, |
268 | dom, DOMLEN, &acc_type)) | |
c0d1968a CV |
269 | goto got_it; |
270 | } | |
271 | } | |
17db1105 | 272 | if (LookupAccountName (NULL, name, sid, SIDLEN, dom, DOMLEN, &acc_type) |
c0d1968a CV |
273 | && legal_sid_type (acc_type)) |
274 | goto got_it; | |
275 | if (acc_type == SidTypeDomain) | |
276 | { | |
277 | strcat (strcat (strcpy (domuser, dom), "\\"), name); | |
17db1105 | 278 | if (LookupAccountName (NULL, domuser, sid, SIDLEN, dom, DOMLEN,&acc_type)) |
c0d1968a CV |
279 | goto got_it; |
280 | } | |
c90e1cf1 | 281 | debug_printf ("LookupAccountName (%s) %E", name); |
c0d1968a CV |
282 | __seterrno (); |
283 | return FALSE; | |
284 | ||
285 | got_it: | |
c90e1cf1 CF |
286 | debug_printf ("sid : [%d]", *GetSidSubAuthority ((PSID) sid, |
287 | *GetSidSubAuthorityCount ((PSID) sid) - 1)); | |
c0d1968a CV |
288 | |
289 | if (ret_sid) | |
290 | memcpy (ret_sid, sid, sidlen); | |
291 | ||
292 | return TRUE; | |
293 | } | |
3c8e92d9 | 294 | |
17db1105 CV |
295 | #undef SIDLEN |
296 | #undef DOMLEN | |
2e8abfc1 | 297 | #endif //unused |
17db1105 | 298 | |
3c8e92d9 | 299 | int |
153e83c6 | 300 | set_process_privilege (const char *privilege, bool enable, bool use_thread) |
3c8e92d9 CV |
301 | { |
302 | HANDLE hToken = NULL; | |
303 | LUID restore_priv; | |
1fcc912f | 304 | TOKEN_PRIVILEGES new_priv, orig_priv; |
3c8e92d9 | 305 | int ret = -1; |
1fcc912f | 306 | DWORD size; |
3c8e92d9 | 307 | |
153e83c6 CV |
308 | if ((use_thread |
309 | && !OpenThreadToken (GetCurrentThread (), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, | |
310 | 0, &hToken)) | |
311 | ||(!use_thread | |
312 | && !OpenProcessToken (hMainProc, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, | |
313 | &hToken))) | |
3c8e92d9 CV |
314 | { |
315 | __seterrno (); | |
316 | goto out; | |
317 | } | |
318 | ||
319 | if (!LookupPrivilegeValue (NULL, privilege, &restore_priv)) | |
320 | { | |
321 | __seterrno (); | |
322 | goto out; | |
323 | } | |
324 | ||
325 | new_priv.PrivilegeCount = 1; | |
326 | new_priv.Privileges[0].Luid = restore_priv; | |
327 | new_priv.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0; | |
328 | ||
1fcc912f | 329 | if (!AdjustTokenPrivileges (hToken, FALSE, &new_priv, |
1ff9f4b9 | 330 | sizeof orig_priv, &orig_priv, &size)) |
1fcc912f CV |
331 | { |
332 | __seterrno (); | |
333 | goto out; | |
334 | } | |
335 | /* AdjustTokenPrivileges returns TRUE even if the privilege could not | |
c90e1cf1 | 336 | be enabled. GetLastError () returns an correct error code, though. */ |
1fcc912f | 337 | if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED) |
3c8e92d9 CV |
338 | { |
339 | __seterrno (); | |
340 | goto out; | |
341 | } | |
342 | ||
1fcc912f | 343 | ret = orig_priv.Privileges[0].Attributes == SE_PRIVILEGE_ENABLED ? 1 : 0; |
3c8e92d9 CV |
344 | |
345 | out: | |
346 | if (hToken) | |
347 | CloseHandle (hToken); | |
348 | ||
96edd0a9 | 349 | syscall_printf ("%d = set_process_privilege (%s, %d)", ret, privilege, enable); |
3c8e92d9 CV |
350 | return ret; |
351 | } | |
73d97618 CV |
352 | |
353 | /* | |
354 | * Function to return a common SECURITY_DESCRIPTOR * that | |
355 | * allows all access. | |
356 | */ | |
357 | ||
358 | static NO_COPY SECURITY_DESCRIPTOR *null_sdp = 0; | |
359 | ||
360 | SECURITY_DESCRIPTOR *__stdcall | |
361 | get_null_sd () | |
362 | { | |
363 | static NO_COPY SECURITY_DESCRIPTOR sd; | |
364 | ||
365 | if (null_sdp == 0) | |
366 | { | |
367 | InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION); | |
368 | SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE); | |
369 | null_sdp = &sd; | |
370 | } | |
371 | return null_sdp; | |
372 | } | |
373 | ||
374 | BOOL | |
c61ada9b | 375 | sec_acl (PACL acl, bool original, bool admins, PSID sid1, PSID sid2, DWORD access2) |
73d97618 CV |
376 | { |
377 | size_t acl_len = MAX_DACL_LEN(5); | |
c61ada9b | 378 | cygpsid psid; |
73d97618 CV |
379 | |
380 | if (!InitializeAcl (acl, acl_len, ACL_REVISION)) | |
381 | { | |
382 | debug_printf ("InitializeAcl %E"); | |
383 | return FALSE; | |
384 | } | |
73d97618 CV |
385 | if (sid1) |
386 | if (!AddAccessAllowedAce (acl, ACL_REVISION, | |
387 | GENERIC_ALL, sid1)) | |
b7e66454 | 388 | debug_printf ("AddAccessAllowedAce(sid1) %E"); |
c61ada9b PH |
389 | if (original && (psid = cygheap->user.orig_sid ()) |
390 | && psid != sid1 && psid != well_known_system_sid) | |
391 | if (!AddAccessAllowedAce (acl, ACL_REVISION, | |
392 | GENERIC_ALL, psid)) | |
393 | debug_printf ("AddAccessAllowedAce(original) %E"); | |
394 | if (sid2) | |
395 | if (!AddAccessAllowedAce (acl, ACL_REVISION, | |
396 | access2, sid2)) | |
397 | debug_printf ("AddAccessAllowedAce(sid2) %E"); | |
73d97618 CV |
398 | if (admins) |
399 | if (!AddAccessAllowedAce (acl, ACL_REVISION, | |
400 | GENERIC_ALL, well_known_admins_sid)) | |
401 | debug_printf ("AddAccessAllowedAce(admin) %E"); | |
402 | if (!AddAccessAllowedAce (acl, ACL_REVISION, | |
403 | GENERIC_ALL, well_known_system_sid)) | |
404 | debug_printf ("AddAccessAllowedAce(system) %E"); | |
73d97618 CV |
405 | return TRUE; |
406 | } | |
407 | ||
408 | PSECURITY_ATTRIBUTES __stdcall | |
c61ada9b | 409 | __sec_user (PVOID sa_buf, PSID sid1, PSID sid2, DWORD access2, BOOL inherit) |
73d97618 CV |
410 | { |
411 | PSECURITY_ATTRIBUTES psa = (PSECURITY_ATTRIBUTES) sa_buf; | |
412 | PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) | |
413 | ((char *) sa_buf + sizeof (*psa)); | |
414 | PACL acl = (PACL) ((char *) sa_buf + sizeof (*psa) + sizeof (*psd)); | |
415 | ||
c61ada9b | 416 | if (!wincap.has_security () || !sec_acl (acl, true, true, sid1, sid2, access2)) |
73d97618 CV |
417 | return inherit ? &sec_none : &sec_none_nih; |
418 | ||
419 | if (!InitializeSecurityDescriptor (psd, SECURITY_DESCRIPTOR_REVISION)) | |
420 | debug_printf ("InitializeSecurityDescriptor %E"); | |
421 | ||
422 | /* | |
423 | * Setting the owner lets the created security attribute not work | |
424 | * on NT4 SP3 Server. Don't know why, but the function still does | |
425 | * what it should do also if the owner isn't set. | |
426 | */ | |
427 | #if 0 | |
428 | if (!SetSecurityDescriptorOwner (psd, sid, FALSE)) | |
429 | debug_printf ("SetSecurityDescriptorOwner %E"); | |
430 | #endif | |
431 | ||
432 | if (!SetSecurityDescriptorDacl (psd, TRUE, acl, FALSE)) | |
433 | debug_printf ("SetSecurityDescriptorDacl %E"); | |
434 | ||
435 | psa->nLength = sizeof (SECURITY_ATTRIBUTES); | |
436 | psa->lpSecurityDescriptor = psd; | |
437 | psa->bInheritHandle = inherit; | |
438 | return psa; | |
439 | } |