xref: /aosp_15_r20/external/cronet/third_party/apache-portable-runtime/src/user/win32/userinfo.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "apr_private.h"
18 #include "apr_strings.h"
19 #include "apr_portable.h"
20 #include "apr_user.h"
21 #include "apr_arch_file_io.h"
22 #if APR_HAVE_SYS_TYPES_H
23 #include <sys/types.h>
24 #endif
25 
26 #ifndef _WIN32_WCE
27 /* Internal sid binary to string translation, see MSKB Q131320.
28  * Several user related operations require our SID to access
29  * the registry, but in a string format.  All error handling
30  * depends on IsValidSid(), which internally we better test long
31  * before we get here!
32  */
get_sid_string(char * buf,apr_size_t blen,apr_uid_t id)33 static void get_sid_string(char *buf, apr_size_t blen, apr_uid_t id)
34 {
35     PSID_IDENTIFIER_AUTHORITY psia;
36     DWORD nsa;
37     DWORD sa;
38     int slen;
39 
40     /* Determine authority values (these is a big-endian value,
41      * and NT records the value as hex if the value is > 2^32.)
42      */
43     psia = GetSidIdentifierAuthority(id);
44     nsa =  (DWORD)(psia->Value[5])        + ((DWORD)(psia->Value[4]) <<  8)
45         + ((DWORD)(psia->Value[3]) << 16) + ((DWORD)(psia->Value[2]) << 24);
46     sa  =  (DWORD)(psia->Value[1])        + ((DWORD)(psia->Value[0]) <<  8);
47     if (sa) {
48         slen = apr_snprintf(buf, blen, "S-%d-0x%04x%08x",
49                             SID_REVISION, (unsigned int)sa, (unsigned int)nsa);
50     } else {
51         slen = apr_snprintf(buf, blen, "S-%d-%lu",
52                             SID_REVISION, nsa);
53     }
54 
55     /* Now append all the subauthority strings.
56      */
57     nsa = *GetSidSubAuthorityCount(id);
58     for (sa = 0; sa < nsa; ++sa) {
59         slen += apr_snprintf(buf + slen, blen - slen, "-%lu",
60                              *GetSidSubAuthority(id, sa));
61     }
62 }
63 #endif
64 /* Query the ProfileImagePath from the version-specific branch, where the
65  * regkey uses the user's name on 9x, and user's sid string on NT.
66  */
apr_uid_homepath_get(char ** dirname,const char * username,apr_pool_t * p)67 APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname,
68                                                const char *username,
69                                                apr_pool_t *p)
70 {
71 #ifdef _WIN32_WCE
72     *dirname = apr_pstrdup(p, "/My Documents");
73     return APR_SUCCESS;
74 #else
75     apr_status_t rv;
76     char regkey[MAX_PATH * 2];
77     char *fixch;
78     DWORD keylen;
79     DWORD type;
80     HKEY key;
81 
82     if (apr_os_level >= APR_WIN_NT) {
83         apr_uid_t uid;
84         apr_gid_t gid;
85 
86         if ((rv = apr_uid_get(&uid, &gid, username, p)) != APR_SUCCESS)
87             return rv;
88 
89         strcpy(regkey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\"
90                        "ProfileList\\");
91         keylen = (DWORD)strlen(regkey);
92         get_sid_string(regkey + keylen, sizeof(regkey) - keylen, uid);
93     }
94     else {
95         strcpy(regkey, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\"
96                        "ProfileList\\");
97         keylen = (DWORD)strlen(regkey);
98         apr_cpystrn(regkey + keylen, username, sizeof(regkey) - keylen);
99     }
100 
101     if ((rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey, 0,
102                            KEY_QUERY_VALUE, &key)) != ERROR_SUCCESS)
103         return APR_FROM_OS_ERROR(rv);
104 
105 #if APR_HAS_UNICODE_FS
106     IF_WIN_OS_IS_UNICODE
107     {
108         keylen = sizeof(regkey);
109         rv = RegQueryValueExW(key, L"ProfileImagePath", NULL, &type,
110                                    (void*)regkey, &keylen);
111         RegCloseKey(key);
112         if (rv != ERROR_SUCCESS)
113             return APR_FROM_OS_ERROR(rv);
114         if (type == REG_SZ) {
115             char retdir[MAX_PATH];
116             if ((rv = unicode_to_utf8_path(retdir, sizeof(retdir),
117                                            (apr_wchar_t*)regkey)) != APR_SUCCESS)
118                 return rv;
119             *dirname = apr_pstrdup(p, retdir);
120         }
121         else if (type == REG_EXPAND_SZ) {
122             apr_wchar_t path[MAX_PATH];
123             char retdir[MAX_PATH];
124             ExpandEnvironmentStringsW((apr_wchar_t*)regkey, path,
125                                       sizeof(path) / 2);
126             if ((rv = unicode_to_utf8_path(retdir, sizeof(retdir), path))
127                     != APR_SUCCESS)
128                 return rv;
129             *dirname = apr_pstrdup(p, retdir);
130         }
131         else
132             return APR_ENOENT;
133     }
134 #endif
135 #if APR_HAS_ANSI_FS
136     ELSE_WIN_OS_IS_ANSI
137     {
138         keylen = sizeof(regkey);
139         rv = RegQueryValueEx(key, "ProfileImagePath", NULL, &type,
140                                   (void*)regkey, &keylen);
141         RegCloseKey(key);
142         if (rv != ERROR_SUCCESS)
143             return APR_FROM_OS_ERROR(rv);
144         if (type == REG_SZ) {
145             *dirname = apr_pstrdup(p, regkey);
146         }
147         else if (type == REG_EXPAND_SZ) {
148             char path[MAX_PATH];
149             ExpandEnvironmentStrings(regkey, path, sizeof(path));
150             *dirname = apr_pstrdup(p, path);
151         }
152         else
153             return APR_ENOENT;
154     }
155 #endif /* APR_HAS_ANSI_FS */
156     for (fixch = *dirname; *fixch; ++fixch)
157         if (*fixch == '\\')
158             *fixch = '/';
159     return APR_SUCCESS;
160 #endif /* _WIN32_WCE */
161 }
162 
apr_uid_current(apr_uid_t * uid,apr_gid_t * gid,apr_pool_t * p)163 APR_DECLARE(apr_status_t) apr_uid_current(apr_uid_t *uid,
164                                           apr_gid_t *gid,
165                                           apr_pool_t *p)
166 {
167 #ifdef _WIN32_WCE
168     return APR_ENOTIMPL;
169 #else
170     HANDLE threadtok;
171     DWORD needed;
172     TOKEN_USER *usr;
173     TOKEN_PRIMARY_GROUP *grp;
174 
175     if(!OpenProcessToken(GetCurrentProcess(), STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY, &threadtok)) {
176         return apr_get_os_error();
177     }
178 
179     *uid = NULL;
180     if (!GetTokenInformation(threadtok, TokenUser, NULL, 0, &needed)
181         && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
182         && (usr = apr_palloc(p, needed))
183         && GetTokenInformation(threadtok, TokenUser, usr, needed, &needed))
184         *uid = usr->User.Sid;
185     else
186         return apr_get_os_error();
187 
188     if (!GetTokenInformation(threadtok, TokenPrimaryGroup, NULL, 0, &needed)
189         && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
190         && (grp = apr_palloc(p, needed))
191         && GetTokenInformation(threadtok, TokenPrimaryGroup, grp, needed, &needed))
192         *gid = grp->PrimaryGroup;
193     else
194         return apr_get_os_error();
195 
196     return APR_SUCCESS;
197 #endif
198 }
199 
apr_uid_get(apr_uid_t * uid,apr_gid_t * gid,const char * username,apr_pool_t * p)200 APR_DECLARE(apr_status_t) apr_uid_get(apr_uid_t *uid, apr_gid_t *gid,
201                                       const char *username, apr_pool_t *p)
202 {
203 #ifdef _WIN32_WCE
204     return APR_ENOTIMPL;
205 #else
206     SID_NAME_USE sidtype;
207     char anydomain[256];
208     char *domain;
209     DWORD sidlen = 0;
210     DWORD domlen = sizeof(anydomain);
211     DWORD rv;
212     char *pos;
213 
214     if ((pos = strchr(username, '/'))) {
215         domain = apr_pstrndup(p, username, pos - username);
216         username = pos + 1;
217     }
218     else if ((pos = strchr(username, '\\'))) {
219         domain = apr_pstrndup(p, username, pos - username);
220         username = pos + 1;
221     }
222     else {
223         domain = NULL;
224     }
225     /* Get nothing on the first pass ... need to size the sid buffer
226      */
227     rv = LookupAccountName(domain, username, domain, &sidlen,
228                            anydomain, &domlen, &sidtype);
229     if (sidlen) {
230         /* Give it back on the second pass
231          */
232         *uid = apr_palloc(p, sidlen);
233         domlen = sizeof(anydomain);
234         rv = LookupAccountName(domain, username, *uid, &sidlen,
235                                anydomain, &domlen, &sidtype);
236     }
237     if (!sidlen || !rv) {
238         return apr_get_os_error();
239     }
240     /* There doesn't seem to be a simple way to retrieve the primary group sid
241      */
242     *gid = NULL;
243     return APR_SUCCESS;
244 #endif
245 }
246 
apr_uid_name_get(char ** username,apr_uid_t userid,apr_pool_t * p)247 APR_DECLARE(apr_status_t) apr_uid_name_get(char **username, apr_uid_t userid,
248                                            apr_pool_t *p)
249 {
250 #ifdef _WIN32_WCE
251     *username = apr_pstrdup(p, "Administrator");
252     return APR_SUCCESS;
253 #else
254     SID_NAME_USE type;
255     char name[MAX_PATH], domain[MAX_PATH];
256     DWORD cbname = sizeof(name), cbdomain = sizeof(domain);
257     if (!userid)
258         return APR_EINVAL;
259     if (!LookupAccountSid(NULL, userid, name, &cbname, domain, &cbdomain, &type))
260         return apr_get_os_error();
261     if (type != SidTypeUser && type != SidTypeAlias && type != SidTypeWellKnownGroup)
262         return APR_EINVAL;
263     *username = apr_pstrdup(p, name);
264     return APR_SUCCESS;
265 #endif
266 }
267 
apr_uid_compare(apr_uid_t left,apr_uid_t right)268 APR_DECLARE(apr_status_t) apr_uid_compare(apr_uid_t left, apr_uid_t right)
269 {
270     if (!left || !right)
271         return APR_EINVAL;
272 #ifndef _WIN32_WCE
273     if (!IsValidSid(left) || !IsValidSid(right))
274         return APR_EINVAL;
275     if (!EqualSid(left, right))
276         return APR_EMISMATCH;
277 #endif
278     return APR_SUCCESS;
279 }
280 
281