OSDN Git Service

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