1 /*
2 * $Header$
3 *
4 * Copyright 2008 Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include <windows.h>
28 #include <stdio.h> // for _snprintf
29 #include <malloc.h>
30 #include <stdlib.h>
31
32 extern "C" {
33 #include "cci_debugging.h"
34 #include "ccutils.h"
35 }
36
37 #include "util.h"
38 #include "secure.hxx"
39
40
malloc_alloc_p(size_t size)41 void* malloc_alloc_p(size_t size) {
42 return malloc(size);
43 }
44
free_alloc_p(void * pptr)45 void free_alloc_p(void *pptr) {
46 void **real_pptr = (void**)pptr;
47 if (*real_pptr) {
48 free(*real_pptr);
49 *real_pptr = 0;
50 }
51 }
52
alloc_textual_sid(PSID pSid,LPSTR * pTextualSid)53 extern "C" DWORD alloc_textual_sid(
54 PSID pSid, // binary Sid
55 LPSTR *pTextualSid // buffer for Textual representation of Sid
56 ) {
57 PSID_IDENTIFIER_AUTHORITY psia;
58 DWORD dwSubAuthorities;
59 DWORD dwSidRev = SID_REVISION;
60 DWORD dwCounter;
61 DWORD dwSidSize;
62
63 *pTextualSid = 0;
64
65 //
66 // test if Sid passed in is valid
67 //
68 if(!IsValidSid(pSid)) return ERROR_INVALID_PARAMETER;
69
70 // obtain SidIdentifierAuthority
71 psia = GetSidIdentifierAuthority(pSid);
72
73 // obtain sidsubauthority count
74 dwSubAuthorities =* GetSidSubAuthorityCount(pSid);
75
76 //
77 // compute buffer length
78 // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
79 //
80 dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
81 *pTextualSid = (LPSTR)malloc_alloc_p(dwSidSize);
82 if (!*pTextualSid)
83 return GetLastError();
84
85 LPSTR TextualSid = *pTextualSid;
86
87 //
88 // prepare S-SID_REVISION-
89 //
90 wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
91
92 //
93 // prepare SidIdentifierAuthority
94 //
95 if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
96 {
97 wsprintf(TextualSid + lstrlen(TextualSid),
98 TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
99 (USHORT)psia->Value[0],
100 (USHORT)psia->Value[1],
101 (USHORT)psia->Value[2],
102 (USHORT)psia->Value[3],
103 (USHORT)psia->Value[4],
104 (USHORT)psia->Value[5]);
105 }
106 else
107 {
108 wsprintf(TextualSid + lstrlen(TextualSid), TEXT("%lu"),
109 (ULONG)(psia->Value[5] ) +
110 (ULONG)(psia->Value[4] << 8) +
111 (ULONG)(psia->Value[3] << 16) +
112 (ULONG)(psia->Value[2] << 24) );
113 }
114
115 //
116 // loop through SidSubAuthorities
117 //
118 for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
119 {
120 wsprintf(TextualSid + lstrlen(TextualSid), TEXT("-%lu"),
121 *GetSidSubAuthority(pSid, dwCounter) );
122 }
123 return 0;
124 }
125
alloc_token_user(HANDLE hToken,PTOKEN_USER * pptu)126 DWORD alloc_token_user(HANDLE hToken, PTOKEN_USER *pptu) {
127 DWORD status = 0;
128 DWORD size = 0;
129 *pptu = 0;
130
131 GetTokenInformation(hToken, TokenUser, *pptu, 0, &size);
132 if (size == 0) status = GetLastError();
133
134 if (!status) {
135 if (!(*pptu = (PTOKEN_USER)malloc_alloc_p(size)))
136 status = GetLastError();
137 }
138
139 if (!status) {
140 if (!GetTokenInformation(hToken, TokenUser, *pptu, size, &size))
141 status = GetLastError();
142 }
143
144 if (status && *pptu) {
145 free_alloc_p(pptu);
146 }
147 return status;
148 }
149
150 DWORD
alloc_username(PSID Sid,LPSTR * pname,LPSTR * pdomain=0)151 alloc_username(
152 PSID Sid,
153 LPSTR* pname,
154 LPSTR* pdomain = 0
155 )
156 {
157 DWORD status = 0;
158 DWORD name_len = 0;
159 DWORD domain_len = 0;
160 SID_NAME_USE snu;
161 LPSTR name = 0;
162 LPSTR domain = 0;
163
164 *pname = 0;
165 if (pdomain) *pdomain = 0;
166
167 LookupAccountSidA(NULL, Sid, 0, &name_len, 0, &domain_len, &snu);
168 if ((name_len == 0) || (domain_len == 0)) status = GetLastError();
169
170 if (!status) {
171 if (!(name = (LPSTR)malloc_alloc_p(name_len))) status = GetLastError();
172 }
173
174 if (!status) {
175 if (!(domain = (LPSTR)malloc_alloc_p(domain_len))) status = GetLastError();
176 }
177
178 if (!status) {
179 if (!LookupAccountSidA(NULL, Sid, name, &name_len, domain, &domain_len, &snu)) status = GetLastError();
180 }
181
182 if (status) {
183 if (name) free_alloc_p(&name);
184 if (domain) free_alloc_p(&domain);
185 }
186 else {
187 if (pdomain) {
188 *pname = name;
189 *pdomain = domain;
190 }
191 else {
192 DWORD size = name_len + domain_len + 1;
193 *pname = (LPSTR)malloc_alloc_p(size);
194 if (!*pname) status = GetLastError();
195 else _snprintf(*pname, size, "%s\\%s", name, domain);
196 }
197 }
198 return status;
199 }
200
get_authentication_id(HANDLE hToken,LUID * pAuthId)201 DWORD get_authentication_id(HANDLE hToken, LUID* pAuthId) {
202 TOKEN_STATISTICS ts;
203 DWORD len;
204
205 if (!GetTokenInformation(hToken, TokenStatistics, &ts, sizeof(ts), &len))
206 return GetLastError();
207 *pAuthId = ts.AuthenticationId;
208 return 0;
209 }
210
211 DWORD
alloc_name_9x(LPSTR * pname,LPSTR postfix)212 alloc_name_9x(
213 LPSTR* pname,
214 LPSTR postfix
215 )
216 {
217 char prefix[] = "krbcc";
218 DWORD len = (sizeof(prefix) - 1) + 1 + strlen(postfix) + 1;
219
220 *pname = (LPSTR)malloc_alloc_p(len);
221 if (!*pname) return GetLastError();
222 _snprintf(*pname, len, "%s.%s", prefix, postfix);
223 return 0;
224 }
225
alloc_name_NT(LPSTR * pname,LPSTR postfix)226 DWORD alloc_name_NT(LPSTR* pname, LPSTR postfix) {
227 DWORD status = 0;
228 HANDLE hToken = 0;
229 LUID auth_id;
230 #ifdef _DEBUG
231 PTOKEN_USER ptu = 0;
232 LPSTR name = 0;
233 LPSTR domain = 0;
234 LPSTR sid = 0;
235 #endif
236 char prefix[] = "krbcc";
237 // Play it safe and say 3 characters are needed per 8 bits (byte).
238 // Note that 20 characters are needed for a 64-bit number in
239 // decimal (plus one for the string termination.
240 // and include room for sessionId.
241 char lid[3*sizeof(LUID)+1+5];
242 DWORD sessionId;
243 DWORD len = 0;
244
245 *pname = 0;
246
247 status = SecureClient::Token(hToken);
248
249 if (!status) {
250 status = get_authentication_id(hToken, &auth_id);
251 }
252
253 if (!status) {
254 if (!ProcessIdToSessionId(GetCurrentProcessId(), &sessionId))
255 sessionId = 0;
256 }
257
258 #ifdef _DEBUG
259 if (!status) {status = alloc_token_user(hToken, &ptu);}
260 if (!status) {status = alloc_username(ptu->User.Sid, &name, &domain);}
261 if (!status) {status = alloc_textual_sid(ptu->User.Sid, &sid);}
262 #endif
263
264 if (!status) {
265 _snprintf(lid, sizeof(lid), "%I64u.%u", auth_id, sessionId);
266 lid[sizeof(lid)-1] = 0; // be safe
267
268 len = (sizeof(prefix) - 1) + 1 + strlen(lid) + 1 + strlen(postfix) + 1;
269 *pname = (LPSTR)malloc_alloc_p(len);
270 if (!*pname) status = GetLastError();
271 }
272
273 //
274 // We used to allocate a name of the form:
275 // "prefix.domain.name.sid.lid.postfix" (usually under 80
276 // characters, depending on username). However, XP thought this
277 // was "invalid" (too long?) for some reason.
278 //
279 // Therefore, we now use "prefix.lid.postfix"
280 // and for Terminal server we use "prefix.lid.sessionId.postfix"
281 //
282
283 if (!status) {
284 _snprintf(*pname, len, "%s.%s.%s", prefix, lid, postfix);
285 }
286
287 #ifdef _DEBUG
288 if (sid)
289 free_alloc_p(&sid);
290 if (name)
291 free_alloc_p(&name);
292 if (domain)
293 free_alloc_p(&domain);
294 if (ptu)
295 free_alloc_p(&ptu);
296 #endif
297 if (hToken && hToken != INVALID_HANDLE_VALUE)
298 CloseHandle(hToken);
299 if (status && *pname)
300 free_alloc_p(pname);
301 return status;
302 }
303
alloc_name(LPSTR * pname,LPSTR postfix,BOOL isNT)304 extern "C" DWORD alloc_name(LPSTR* pname, LPSTR postfix, BOOL isNT) {
305 return isNT ? alloc_name_NT(pname, postfix) :
306 alloc_name_9x(pname, postfix);
307 }
308
alloc_own_security_descriptor_NT(PSECURITY_DESCRIPTOR * ppsd)309 extern "C" DWORD alloc_own_security_descriptor_NT(PSECURITY_DESCRIPTOR* ppsd) {
310 DWORD status = 0;
311 HANDLE hToken = 0;
312 PTOKEN_USER ptu = 0;
313 PSID pSid = 0;
314 PACL pAcl = 0;
315 DWORD size = 0;
316 SECURITY_DESCRIPTOR sd;
317
318 *ppsd = 0;
319
320 if (!status) {status = SecureClient::Token(hToken);}
321
322 // Get SID:
323 if (!status) {status = alloc_token_user(hToken, &ptu);}
324
325 if (!status) {
326 size = GetLengthSid(ptu->User.Sid);
327 pSid = (PSID) malloc_alloc_p(size);
328 if (!pSid) status = GetLastError();
329 }
330 if (!status) {
331 if (!CopySid(size, pSid, ptu->User.Sid)) status = GetLastError();
332 }
333
334 if (!status) {
335 // Prepare ACL:
336 size = sizeof(ACL);
337 // Add an ACE:
338 size += sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(pSid);
339 pAcl = (PACL) malloc_alloc_p(size);
340 if (!pAcl) status = GetLastError();
341 }
342
343 if (!status) {
344 if (!InitializeAcl(pAcl, size, ACL_REVISION)) status = GetLastError();
345 }
346
347 if (!status) {
348 if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, pSid)) status = GetLastError();
349 }
350
351 if (!status) {
352 // Prepare SD itself:
353 if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) status = GetLastError();
354 }
355
356 if (!status) {
357 if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) status = GetLastError();
358 }
359
360 if (!status) {
361 if (!SetSecurityDescriptorOwner(&sd, pSid, FALSE)) status = GetLastError();
362 }
363
364 if (!status) {
365 if (!IsValidSecurityDescriptor(&sd)) status = ERROR_INVALID_PARAMETER;
366 }
367
368 if (!status) {
369 // We now have a SD. Let's copy it.
370 {
371 // This should not succeed. Instead it should give us the size.
372 BOOL ok = MakeSelfRelativeSD(&sd, 0, &size);
373 }
374 if (size == 0) status = GetLastError();
375 }
376
377 if (!status) {
378 *ppsd = (PSECURITY_DESCRIPTOR) malloc_alloc_p(size);
379 if (!*ppsd) status = GetLastError();
380 }
381
382 if (!status) {
383 if (!MakeSelfRelativeSD(&sd, *ppsd, &size)) status = GetLastError();
384 }
385
386 if (ptu) free_alloc_p(&ptu);
387 if (pSid) free_alloc_p(&pSid);
388 if (pAcl) free_alloc_p(&pAcl);
389 if (hToken && hToken != INVALID_HANDLE_VALUE) CloseHandle(hToken);
390 if (status && *ppsd) free_alloc_p(ppsd);
391 return status;
392 }
393
394 DWORD
alloc_module_file_name(char * module,char ** pname)395 alloc_module_file_name(
396 char* module,
397 char** pname
398 )
399 {
400 const DWORD max = 8192;
401 DWORD status = 0;
402 DWORD got = 0;
403 DWORD size = 512; // use low number to test...
404 HMODULE h = 0;
405 BOOL ok = FALSE;
406 char* name = 0;
407
408 if (!pname)
409 return ERROR_INVALID_PARAMETER;
410 *pname = 0;
411
412 h = GetModuleHandle(module);
413
414 if (!h) return GetLastError();
415
416 // We assume size < max and size > 0
417 while (!status && !ok) {
418 if (size > max) {
419 // XXX - Assert?
420 status = ERROR_INVALID_DATA;
421 continue;
422 }
423 if (name) free_alloc_p(&name);
424 name = (char*)malloc_alloc_p(size + 1);
425 if (!name) {
426 status = ERROR_NOT_ENOUGH_MEMORY;
427 continue;
428 }
429 name[size] = 0;
430 got = GetModuleFileName(h, name, size);
431 if (!got) {
432 status = GetLastError();
433 // sanity check:
434 if (!status) {
435 // XXX - print nasty message...assert?
436 status = ERROR_INVALID_DATA;
437 }
438 continue;
439 }
440 // To know we're ok, we need to verify that what we got
441 // was bigger than GetModuleSize thought it got.
442 ok = got && (got < size) && !name[got];
443 size *= 2;
444 }
445 if (status && name)
446 free_alloc_p(&name);
447 else
448 *pname = name;
449 return status;
450 }
451
452 DWORD
alloc_module_dir_name(char * module,char ** pname)453 alloc_module_dir_name(
454 char* module,
455 char** pname
456 )
457 {
458 DWORD status = alloc_module_file_name(module, pname);
459 if (!status) {
460 char* name = *pname;
461 char* p = name + strlen(name);
462 while ((p >= name) && (*p != '\\') && (*p != '/')) p--;
463 if (p < name) {
464 free_alloc_p(pname);
465 status = ERROR_INVALID_DATA;
466 } else {
467 *p = 0;
468 }
469 }
470 return status;
471 }
472
473 DWORD
alloc_module_dir_name_with_file(char * module,char * file,char ** pname)474 alloc_module_dir_name_with_file(
475 char* module,
476 char* file,
477 char** pname
478 )
479 {
480 DWORD status = alloc_module_dir_name(module, pname);
481 if (!status) {
482 char* name = *pname;
483 size_t name_size = strlen(name);
484 size_t size = name_size + 1 + strlen(file) + 1;
485 char* result = (char*)malloc_alloc_p(size);
486 if (!result) {
487 status = ERROR_NOT_ENOUGH_MEMORY;
488 free_alloc_p(pname);
489 } else {
490 strcpy(result, name);
491 result[name_size] = '\\';
492 strcpy(result + name_size + 1, file);
493 free_alloc_p(pname);
494 *pname = result;
495 }
496 }
497 return status;
498 }
499
alloc_cmdline_2_args(char * prog,char * arg1,char * arg2,char ** pname)500 DWORD alloc_cmdline_2_args(char* prog,
501 char* arg1,
502 char* arg2,
503 char** pname) {
504 DWORD status = 0;
505 size_t size = strlen(prog) + strlen(arg1) + strlen(arg2) + 4;
506 char* result = (char*)malloc_alloc_p(size);
507 if (!result) {
508 status = ERROR_NOT_ENOUGH_MEMORY;
509 }
510 else {
511 strcpy(result, prog);
512 strcat(result, " ");
513 strcat(result, arg1);
514 strcat(result, " ");
515 strcat(result, arg2);
516 *pname = result;
517 }
518 cci_debug_printf("%s made <%s>", __FUNCTION__, result);
519 return status;
520 }
521