1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "sandbox/win/src/acl.h"
6
7#include <aclapi.h>
8#include <sddl.h>
9
10#include "base/logging.h"
11
12namespace sandbox {
13
14bool GetDefaultDacl(
15    HANDLE token,
16    scoped_ptr<TOKEN_DEFAULT_DACL, base::FreeDeleter>* default_dacl) {
17  if (token == NULL)
18    return false;
19
20  DCHECK(default_dacl != NULL);
21
22  unsigned long length = 0;
23  ::GetTokenInformation(token, TokenDefaultDacl, NULL, 0, &length);
24  if (length == 0) {
25    NOTREACHED();
26    return false;
27  }
28
29  TOKEN_DEFAULT_DACL* acl =
30      reinterpret_cast<TOKEN_DEFAULT_DACL*>(malloc(length));
31  default_dacl->reset(acl);
32
33  if (!::GetTokenInformation(token, TokenDefaultDacl, default_dacl->get(),
34                             length, &length))
35      return false;
36
37  return true;
38}
39
40bool AddSidToDacl(const Sid& sid, ACL* old_dacl, ACCESS_MODE access_mode,
41                  ACCESS_MASK access, ACL** new_dacl) {
42  EXPLICIT_ACCESS new_access = {0};
43  new_access.grfAccessMode = access_mode;
44  new_access.grfAccessPermissions = access;
45  new_access.grfInheritance = NO_INHERITANCE;
46
47  new_access.Trustee.pMultipleTrustee = NULL;
48  new_access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
49  new_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
50  new_access.Trustee.ptstrName = reinterpret_cast<LPWSTR>(
51                                    const_cast<SID*>(sid.GetPSID()));
52
53  if (ERROR_SUCCESS != ::SetEntriesInAcl(1, &new_access, old_dacl, new_dacl))
54    return false;
55
56  return true;
57}
58
59bool AddSidToDefaultDacl(HANDLE token, const Sid& sid, ACCESS_MASK access) {
60  if (token == NULL)
61    return false;
62
63  scoped_ptr<TOKEN_DEFAULT_DACL, base::FreeDeleter> default_dacl;
64  if (!GetDefaultDacl(token, &default_dacl))
65    return false;
66
67  ACL* new_dacl = NULL;
68  if (!AddSidToDacl(sid, default_dacl->DefaultDacl, GRANT_ACCESS, access,
69                    &new_dacl))
70    return false;
71
72  TOKEN_DEFAULT_DACL new_token_dacl = {0};
73  new_token_dacl.DefaultDacl = new_dacl;
74
75  BOOL ret = ::SetTokenInformation(token, TokenDefaultDacl, &new_token_dacl,
76                                   sizeof(new_token_dacl));
77  ::LocalFree(new_dacl);
78  return (TRUE == ret);
79}
80
81bool AddUserSidToDefaultDacl(HANDLE token, ACCESS_MASK access) {
82  DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
83  TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(malloc(size));
84
85  scoped_ptr<TOKEN_USER, base::FreeDeleter> token_user_ptr(token_user);
86
87  if (!::GetTokenInformation(token, TokenUser, token_user, size, &size))
88    return false;
89
90  return AddSidToDefaultDacl(token,
91                             reinterpret_cast<SID*>(token_user->User.Sid),
92                             access);
93}
94
95bool AddKnownSidToObject(HANDLE object, SE_OBJECT_TYPE object_type,
96                         const Sid& sid, ACCESS_MODE access_mode,
97                         ACCESS_MASK access) {
98  PSECURITY_DESCRIPTOR descriptor = NULL;
99  PACL old_dacl = NULL;
100  PACL new_dacl = NULL;
101
102  if (ERROR_SUCCESS != ::GetSecurityInfo(object, object_type,
103                                         DACL_SECURITY_INFORMATION, NULL, NULL,
104                                         &old_dacl, NULL, &descriptor))
105    return false;
106
107  if (!AddSidToDacl(sid.GetPSID(), old_dacl, access_mode, access, &new_dacl)) {
108    ::LocalFree(descriptor);
109    return false;
110  }
111
112  DWORD result = ::SetSecurityInfo(object, object_type,
113                                   DACL_SECURITY_INFORMATION, NULL, NULL,
114                                   new_dacl, NULL);
115
116  ::LocalFree(new_dacl);
117  ::LocalFree(descriptor);
118
119  if (ERROR_SUCCESS != result)
120    return false;
121
122  return true;
123}
124
125}  // namespace sandbox
126