OSDN Git Service

2002-03-01 David O'Brien <obrien@FreeBSD.org>
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / sec_helper.cc
1 /* sec_helper.cc: NT security helper functions
2
3    Copyright 2000, 2001, 2002 Red Hat, Inc.
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>
18 #include <errno.h>
19 #include <limits.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/acl.h>
23 #include <ctype.h>
24 #include <wingdi.h>
25 #include <winuser.h>
26 #include <wininet.h>
27 #include "cygerrno.h"
28 #include "perprocess.h"
29 #include "security.h"
30 #include "fhandler.h"
31 #include "path.h"
32 #include "dtable.h"
33 #include "sync.h"
34 #include "sigproc.h"
35 #include "pinfo.h"
36 #include "cygheap.h"
37
38 SID_IDENTIFIER_AUTHORITY sid_auth[] = {
39         {SECURITY_NULL_SID_AUTHORITY},
40         {SECURITY_WORLD_SID_AUTHORITY},
41         {SECURITY_LOCAL_SID_AUTHORITY},
42         {SECURITY_CREATOR_SID_AUTHORITY},
43         {SECURITY_NON_UNIQUE_AUTHORITY},
44         {SECURITY_NT_AUTHORITY}
45 };
46
47 cygsid well_known_null_sid ("S-1-0-0");
48 cygsid well_known_world_sid ("S-1-1-0");
49 cygsid well_known_local_sid ("S-1-2-0");
50 cygsid well_known_creator_owner_sid ("S-1-3-0");
51 cygsid well_known_dialup_sid ("S-1-5-1");
52 cygsid well_known_network_sid ("S-1-5-2");
53 cygsid well_known_batch_sid ("S-1-5-3");
54 cygsid well_known_interactive_sid ("S-1-5-4");
55 cygsid well_known_service_sid ("S-1-5-6");
56 cygsid well_known_authenticated_users_sid ("S-1-5-11");
57 cygsid well_known_system_sid ("S-1-5-18");
58 cygsid well_known_admins_sid ("S-1-5-32-544");
59
60 char *
61 cygsid::string (char *nsidstr) const
62 {
63   char t[32];
64   DWORD i;
65
66   if (!psid || !nsidstr)
67     return NULL;
68   strcpy (nsidstr, "S-1-");
69   __small_sprintf(t, "%u", GetSidIdentifierAuthority (psid)->Value[5]);
70   strcat (nsidstr, t);
71   for (i = 0; i < *GetSidSubAuthorityCount (psid); ++i)
72     {
73       __small_sprintf(t, "-%lu", *GetSidSubAuthority (psid, i));
74       strcat (nsidstr, t);
75     }
76   return nsidstr;
77 }
78
79 PSID
80 cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r)
81 {
82   DWORD i;
83
84   if (s > 5 || cnt < 1 || cnt > 8)
85     {
86       psid = NO_SID;
87       return NULL;
88     }
89   set ();
90   InitializeSid(psid, &sid_auth[s], cnt);
91   for (i = 0; i < cnt; ++i)
92     memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD));
93   return psid;
94 }
95
96 const PSID
97 cygsid::getfromstr (const char *nsidstr)
98 {
99   char sid_buf[256];
100   char *t, *lasts;
101   DWORD cnt = 0;
102   DWORD s = 0;
103   DWORD i, r[8];
104
105   if (!nsidstr || strncmp (nsidstr, "S-1-", 4))
106     {
107       psid = NO_SID;
108       return NULL;
109     }
110
111   strcpy (sid_buf, nsidstr);
112
113   for (t = sid_buf + 4, i = 0;
114        cnt < 8 && (t = strtok_r (t, "-", &lasts));
115        t = NULL, ++i)
116     if (i == 0)
117       s = strtoul (t, NULL, 10);
118     else
119       r[cnt++] = strtoul (t, NULL, 10);
120
121   return get_sid (s, cnt, r);
122 }
123
124 BOOL
125 cygsid::getfrompw (const struct passwd *pw)
126 {
127   char *sp = (pw && pw->pw_gecos) ? strrchr (pw->pw_gecos, ',') : NULL;
128   return (*this = sp ? sp + 1 : "") != NULL;
129 }
130
131 BOOL
132 cygsid::getfromgr (const struct __group16 *gr)
133 {
134   char *sp = (gr && gr->gr_passwd) ? gr->gr_passwd : NULL;
135   return (*this = sp ?: "") != NULL;
136 }
137
138 int
139 cygsid::get_id (BOOL search_grp, int *type)
140 {
141   if (!psid)
142     {
143       set_errno (EINVAL);
144       return -1;
145     }
146   if (!IsValidSid (psid))
147     {
148       __seterrno ();
149       small_printf ("IsValidSid failed with %E");
150       return -1;
151     }
152
153   /* First try to get SID from passwd or group entry */
154   if (allow_ntsec)
155     {
156       cygsid sid;
157       int id = -1;
158
159       if (!search_grp)
160         {
161           struct passwd *pw;
162           for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx)
163             {
164               if (sid.getfrompw (pw) && sid == psid)
165                 {
166                   id = pw->pw_uid;
167                   break;
168                 }
169             }
170           if (id >= 0)
171             {
172               if (type)
173                 *type = USER;
174               return id;
175             }
176         }
177       if (search_grp || type)
178         {
179           struct __group16 *gr;
180           for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
181             {
182               if (sid.getfromgr (gr) && sid == psid)
183                 {
184                   id = gr->gr_gid;
185                   break;
186                 }
187             }
188           if (id >= 0)
189             {
190               if (type)
191                 *type = GROUP;
192               return id;
193             }
194         }
195     }
196
197   /* We use the RID as default UID/GID */
198   int id = *GetSidSubAuthority(psid, *GetSidSubAuthorityCount(psid) - 1);
199
200   /*
201    * The RID maybe -1 if accountname == computername.
202    * In this case we search for the accountname in the passwd and group files.
203    * If type is needed, we search in each case.
204    */
205   if (id == -1 || type)
206     {
207       char account[UNLEN + 1];
208       char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
209       DWORD acc_len = UNLEN + 1;
210       DWORD dom_len = INTERNET_MAX_HOST_NAME_LENGTH + 1;
211       SID_NAME_USE acc_type;
212
213       if (!LookupAccountSid (NULL, psid, account, &acc_len,
214                              domain, &dom_len, &acc_type))
215         {
216           __seterrno ();
217           return -1;
218         }
219
220       switch (acc_type)
221         {
222           case SidTypeGroup:
223           case SidTypeAlias:
224           case SidTypeWellKnownGroup:
225             if (type)
226               *type = GROUP;
227             if (id == -1)
228               {
229                 struct __group16 *gr = getgrnam (account);
230                 if (gr)
231                   id = gr->gr_gid;
232               }
233             break;
234           case SidTypeUser:
235             if (type)
236               *type = USER;
237             if (id == -1)
238               {
239                 struct passwd *pw = getpwnam (account);
240                 if (pw)
241                   id = pw->pw_uid;
242               }
243             break;
244           default:
245             break;
246         }
247     }
248   if (id == -1)
249     id = getuid ();
250   return id;
251 }
252
253 BOOL
254 is_grp_member (__uid16_t uid, __gid16_t gid)
255 {
256   extern int getgroups (int, __gid16_t *, __gid16_t, const char *);
257   BOOL grp_member = TRUE;
258
259   struct passwd *pw = getpwuid (uid);
260   __gid16_t grps[NGROUPS_MAX];
261   int cnt = getgroups (NGROUPS_MAX, grps,
262                        pw ? pw->pw_gid : myself->gid,
263                        pw ? pw->pw_name : cygheap->user.name ());
264   int i;
265   for (i = 0; i < cnt; ++i)
266     if (grps[i] == gid)
267       break;
268   grp_member = (i < cnt);
269   return grp_member;
270 }
271
272 #define SIDLEN  (sidlen = MAX_SID_LEN, &sidlen)
273 #define DOMLEN  (domlen = INTERNET_MAX_HOST_NAME_LENGTH, &domlen)
274
275 BOOL
276 lookup_name (const char *name, const char *logsrv, PSID ret_sid)
277 {
278   cygsid sid;
279   DWORD sidlen;
280   char domuser[INTERNET_MAX_HOST_NAME_LENGTH + UNLEN + 2];
281   char dom[INTERNET_MAX_HOST_NAME_LENGTH + 1];
282   DWORD domlen;
283   SID_NAME_USE acc_type;
284
285   debug_printf ("name  : %s", name ? name : "NULL");
286
287   if (!name)
288     return FALSE;
289
290   if (cygheap->user.domain ())
291     {
292       strcat (strcat (strcpy (domuser, cygheap->user.domain ()), "\\"), name);
293       if (LookupAccountName (NULL, domuser, sid, SIDLEN, dom, DOMLEN, &acc_type)
294           && legal_sid_type (acc_type))
295         goto got_it;
296       if (logsrv && *logsrv
297           && LookupAccountName (logsrv, domuser, sid, SIDLEN,
298                                 dom, DOMLEN, &acc_type)
299           && legal_sid_type (acc_type))
300         goto got_it;
301     }
302   if (logsrv && *logsrv)
303     {
304       if (LookupAccountName (logsrv, name, sid, SIDLEN, dom, DOMLEN, &acc_type)
305           && legal_sid_type (acc_type))
306         goto got_it;
307       if (acc_type == SidTypeDomain)
308         {
309           strcat (strcat (strcpy (domuser, dom), "\\"), name);
310           if (LookupAccountName (logsrv, domuser, sid, SIDLEN,
311                                  dom, DOMLEN, &acc_type))
312             goto got_it;
313         }
314     }
315   if (LookupAccountName (NULL, name, sid, SIDLEN, dom, DOMLEN, &acc_type)
316       && legal_sid_type (acc_type))
317     goto got_it;
318   if (acc_type == SidTypeDomain)
319     {
320       strcat (strcat (strcpy (domuser, dom), "\\"), name);
321       if (LookupAccountName (NULL, domuser, sid, SIDLEN, dom, DOMLEN,&acc_type))
322         goto got_it;
323     }
324   debug_printf ("LookupAccountName(%s) %E", name);
325   __seterrno ();
326   return FALSE;
327
328 got_it:
329   debug_printf ("sid : [%d]", *GetSidSubAuthority((PSID) sid,
330                               *GetSidSubAuthorityCount((PSID) sid) - 1));
331
332   if (ret_sid)
333     memcpy (ret_sid, sid, sidlen);
334
335   return TRUE;
336 }
337
338 #undef SIDLEN
339 #undef DOMLEN
340
341 int
342 set_process_privilege (const char *privilege, BOOL enable)
343 {
344   HANDLE hToken = NULL;
345   LUID restore_priv;
346   TOKEN_PRIVILEGES new_priv, orig_priv;
347   int ret = -1;
348   DWORD size;
349
350   if (!OpenProcessToken (hMainProc, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
351                          &hToken))
352     {
353       __seterrno ();
354       goto out;
355     }
356
357   if (!LookupPrivilegeValue (NULL, privilege, &restore_priv))
358     {
359       __seterrno ();
360       goto out;
361     }
362
363   new_priv.PrivilegeCount = 1;
364   new_priv.Privileges[0].Luid = restore_priv;
365   new_priv.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
366
367   if (!AdjustTokenPrivileges (hToken, FALSE, &new_priv,
368                               sizeof orig_priv, &orig_priv, &size))
369     {
370       __seterrno ();
371       goto out;
372     }
373   /* AdjustTokenPrivileges returns TRUE even if the privilege could not
374      be enabled. GetLastError() returns an correct error code, though. */
375   if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED)
376     {
377       debug_printf ("Privilege %s couldn't be assigned", privilege);
378       __seterrno ();
379       goto out;
380     }
381
382   ret = orig_priv.Privileges[0].Attributes == SE_PRIVILEGE_ENABLED ? 1 : 0;
383
384 out:
385   if (hToken)
386     CloseHandle (hToken);
387
388   syscall_printf ("%d = set_process_privilege (%s, %d)",ret, privilege, enable);
389   return ret;
390 }