xref: /freebsd/crypto/krb5/src/ccapi/common/win/OldCC/util.cxx (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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