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 */ 33static 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 */ 67APR_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 163APR_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 200APR_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 247APR_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 268APR_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