This source file includes following definitions.
- tsrm_win32_ctor
- tsrm_win32_dtor
- tsrm_win32_startup
- tsrm_win32_shutdown
- tsrm_win32_get_path_sid_key
- tsrm_win32_get_token_sid
- tsrm_win32_access
- process_get
- shm_get
- dupHandle
- popen
- popen_ex
- pclose
- shmget
- shmat
- shmdt
- shmctl
- realpath
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <io.h>
24 #include <process.h>
25 #include <time.h>
26 #include <errno.h>
27
28 #define TSRM_INCLUDE_FULL_WINDOWS_HEADERS
29 #include "SAPI.h"
30 #include "TSRM.h"
31
32 #ifdef TSRM_WIN32
33 #include <Sddl.h>
34 #include "tsrm_win32.h"
35 #include "zend_virtual_cwd.h"
36
37 #ifdef ZTS
38 static ts_rsrc_id win32_globals_id;
39 #else
40 static tsrm_win32_globals win32_globals;
41 #endif
42
43 static void tsrm_win32_ctor(tsrm_win32_globals *globals TSRMLS_DC)
44 {
45 globals->process = NULL;
46 globals->shm = NULL;
47 globals->process_size = 0;
48 globals->shm_size = 0;
49 globals->comspec = _strdup((GetVersion()<0x80000000)?"cmd.exe":"command.com");
50
51
52
53
54
55
56
57
58 globals->impersonation_token = INVALID_HANDLE_VALUE;
59 globals->impersonation_token_sid = NULL;
60 }
61
62 static void tsrm_win32_dtor(tsrm_win32_globals *globals TSRMLS_DC)
63 {
64 shm_pair *ptr;
65
66 if (globals->process) {
67 free(globals->process);
68 }
69
70 if (globals->shm) {
71 for (ptr = globals->shm; ptr < (globals->shm + globals->shm_size); ptr++) {
72 UnmapViewOfFile(ptr->addr);
73 CloseHandle(ptr->segment);
74 UnmapViewOfFile(ptr->descriptor);
75 CloseHandle(ptr->info);
76 }
77 free(globals->shm);
78 }
79
80 free(globals->comspec);
81
82 if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE ) {
83 CloseHandle(globals->impersonation_token);
84 }
85 if (globals->impersonation_token_sid) {
86 free(globals->impersonation_token_sid);
87 }
88 }
89
90 TSRM_API void tsrm_win32_startup(void)
91 {
92 #ifdef ZTS
93 ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor);
94 #else
95 tsrm_win32_ctor(&win32_globals TSRMLS_CC);
96 #endif
97 }
98
99 TSRM_API void tsrm_win32_shutdown(void)
100 {
101 #ifndef ZTS
102 tsrm_win32_dtor(&win32_globals TSRMLS_CC);
103 #endif
104 }
105
106 char * tsrm_win32_get_path_sid_key(const char *pathname TSRMLS_DC)
107 {
108 PSID pSid = TWG(impersonation_token_sid);
109 DWORD sid_len = pSid ? GetLengthSid(pSid) : 0;
110 TCHAR *ptcSid = NULL;
111 char *bucket_key = NULL;
112
113 if (!pSid) {
114 bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname) + 1);
115 if (!bucket_key) {
116 return NULL;
117 }
118 memcpy(bucket_key, pathname, strlen(pathname));
119 return bucket_key;
120 }
121
122 if (!ConvertSidToStringSid(pSid, &ptcSid)) {
123 return NULL;
124 }
125
126 bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname) + strlen(ptcSid) + 1);
127 if (!bucket_key) {
128 LocalFree(ptcSid);
129 return NULL;
130 }
131
132 memcpy(bucket_key, ptcSid, strlen(ptcSid));
133 memcpy(bucket_key + strlen(ptcSid), pathname, strlen(pathname) + 1);
134
135 LocalFree(ptcSid);
136 return bucket_key;
137 }
138
139
140 PSID tsrm_win32_get_token_sid(HANDLE hToken)
141 {
142 BOOL bSuccess = FALSE;
143 DWORD dwLength = 0;
144 PTOKEN_USER pTokenUser = NULL;
145 PSID sid;
146 PSID *ppsid = &sid;
147 DWORD sid_len;
148 PSID pResultSid = NULL;
149
150
151 if (!GetTokenInformation(
152 hToken, TokenUser, (LPVOID) pTokenUser, 0, &dwLength)) {
153 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
154 goto Finished;
155 }
156
157 pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
158 if (pTokenUser == NULL) {
159 goto Finished;
160 }
161 }
162
163
164 if (!GetTokenInformation(
165 hToken, TokenUser, (LPVOID) pTokenUser, dwLength, &dwLength)) {
166 goto Finished;
167 }
168
169 sid_len = GetLengthSid(pTokenUser->User.Sid);
170
171
172 pResultSid = malloc(sid_len);
173 if (!pResultSid) {
174 goto Finished;
175 }
176 if (!CopySid(sid_len, pResultSid, pTokenUser->User.Sid)) {
177 goto Finished;
178 }
179 HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
180 return pResultSid;
181
182 Finished:
183 if (pResultSid) {
184 free(pResultSid);
185 }
186
187 if (pTokenUser != NULL) {
188 HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
189 }
190 return NULL;
191 }
192
193 TSRM_API int tsrm_win32_access(const char *pathname, int mode TSRMLS_DC)
194 {
195 time_t t;
196 HANDLE thread_token = NULL;
197 PSID token_sid;
198 SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
199 GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
200 DWORD priv_set_length = sizeof(PRIVILEGE_SET);
201
202 PRIVILEGE_SET privilege_set = {0};
203 DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
204 BYTE * psec_desc = NULL;
205 BOOL fAccess = FALSE;
206
207 BOOL bucket_key_alloc = FALSE;
208 realpath_cache_bucket * bucket = NULL;
209 char * real_path = NULL;
210
211 if (mode == 1 ) {
212 DWORD type;
213 return GetBinaryType(pathname, &type) ? 0 : -1;
214 } else {
215 if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
216 real_path = (char *)malloc(MAX_PATH);
217 if(tsrm_realpath(pathname, real_path TSRMLS_CC) == NULL) {
218 goto Finished;
219 }
220 pathname = real_path;
221 }
222
223 if(access(pathname, mode)) {
224 free(real_path);
225 return errno;
226 }
227
228
229 if (mode == 0) {
230 free(real_path);
231 return 0;
232 }
233
234
235
236
237
238
239
240
241
242
243
244 if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
245 DWORD err = GetLastError();
246 if (GetLastError() == ERROR_NO_TOKEN) {
247 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
248 TWG(impersonation_token) = NULL;
249 goto Finished;
250 }
251 }
252 }
253
254
255 token_sid = tsrm_win32_get_token_sid(thread_token);
256 if (!token_sid) {
257 if (TWG(impersonation_token_sid)) {
258 free(TWG(impersonation_token_sid));
259 }
260 TWG(impersonation_token_sid) = NULL;
261 goto Finished;
262 }
263
264
265 if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
266 if (TWG(impersonation_token_sid)) {
267 free(TWG(impersonation_token_sid));
268 }
269 TWG(impersonation_token_sid) = token_sid;
270
271
272 if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
273 goto Finished;
274 }
275 } else {
276
277 free(token_sid);
278 }
279
280 if (CWDG(realpath_cache_size_limit)) {
281 t = time(0);
282 bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
283 if(bucket == NULL && real_path == NULL) {
284
285
286 real_path = (char *)malloc(MAX_PATH);
287 if(tsrm_realpath(pathname, real_path TSRMLS_CC) != NULL) {
288 pathname = real_path;
289 bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
290 }
291 }
292 }
293
294
295 if(mode == 0 || mode > 6) {
296 if(bucket != NULL && bucket->is_rvalid) {
297 fAccess = bucket->is_readable;
298 goto Finished;
299 }
300 desired_access = FILE_GENERIC_READ;
301 } else if(mode <= 2) {
302 if(bucket != NULL && bucket->is_wvalid) {
303 fAccess = bucket->is_writable;
304 goto Finished;
305 }
306 desired_access = FILE_GENERIC_WRITE;
307 } else if(mode <= 4) {
308 if(bucket != NULL && bucket->is_rvalid) {
309 fAccess = bucket->is_readable;
310 goto Finished;
311 }
312 desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
313 } else {
314 if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
315 fAccess = bucket->is_readable & bucket->is_writable;
316 goto Finished;
317 }
318 desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
319 }
320
321 if(TWG(impersonation_token) == NULL) {
322 goto Finished;
323 }
324
325
326 if(GetFileSecurity(pathname, sec_info, NULL, 0, &sec_desc_length)) {
327 goto Finished;
328 }
329
330 psec_desc = (BYTE *)malloc(sec_desc_length);
331 if(psec_desc == NULL ||
332 !GetFileSecurity(pathname, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
333 goto Finished;
334 }
335
336 MapGenericMask(&desired_access, &gen_map);
337
338 if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
339 goto Finished_Impersonate;
340 }
341
342
343 if(bucket != NULL) {
344 if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
345 bucket->is_rvalid = 1;
346 bucket->is_readable = fAccess;
347 }
348 else if(desired_access == FILE_GENERIC_WRITE) {
349 bucket->is_wvalid = 1;
350 bucket->is_writable = fAccess;
351 } else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
352 bucket->is_rvalid = 1;
353 bucket->is_readable = fAccess;
354 bucket->is_wvalid = 1;
355 bucket->is_writable = fAccess;
356 }
357 }
358
359 Finished_Impersonate:
360 if(psec_desc != NULL) {
361 free(psec_desc);
362 psec_desc = NULL;
363 }
364
365 Finished:
366 if(thread_token != NULL) {
367 CloseHandle(thread_token);
368 }
369 if(real_path != NULL) {
370 free(real_path);
371 real_path = NULL;
372 }
373
374 if(fAccess == FALSE) {
375 errno = EACCES;
376 return errno;
377 } else {
378 return 0;
379 }
380 }
381 }
382
383
384 static process_pair *process_get(FILE *stream TSRMLS_DC)
385 {
386 process_pair *ptr;
387 process_pair *newptr;
388
389 for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
390 if (ptr->stream == stream) {
391 break;
392 }
393 }
394
395 if (ptr < (TWG(process) + TWG(process_size))) {
396 return ptr;
397 }
398
399 newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
400 if (newptr == NULL) {
401 return NULL;
402 }
403
404 TWG(process) = newptr;
405 ptr = newptr + TWG(process_size);
406 TWG(process_size)++;
407 return ptr;
408 }
409
410 static shm_pair *shm_get(int key, void *addr)
411 {
412 shm_pair *ptr;
413 shm_pair *newptr;
414 TSRMLS_FETCH();
415
416 for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
417 if (!ptr->descriptor) {
418 continue;
419 }
420 if (!addr && ptr->descriptor->shm_perm.key == key) {
421 break;
422 } else if (ptr->addr == addr) {
423 break;
424 }
425 }
426
427 if (ptr < (TWG(shm) + TWG(shm_size))) {
428 return ptr;
429 }
430
431 newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
432 if (newptr == NULL) {
433 return NULL;
434 }
435
436 TWG(shm) = newptr;
437 ptr = newptr + TWG(shm_size);
438 TWG(shm_size)++;
439 return ptr;
440 }
441
442 static HANDLE dupHandle(HANDLE fh, BOOL inherit) {
443 HANDLE copy, self = GetCurrentProcess();
444 if (!DuplicateHandle(self, fh, self, ©, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
445 return NULL;
446 }
447 return copy;
448 }
449
450 TSRM_API FILE *popen(const char *command, const char *type)
451 {
452 TSRMLS_FETCH();
453
454 return popen_ex(command, type, NULL, NULL TSRMLS_CC);
455 }
456
457 TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env TSRMLS_DC)
458 {
459 FILE *stream = NULL;
460 int fno, type_len = strlen(type), read, mode;
461 STARTUPINFO startup;
462 PROCESS_INFORMATION process;
463 SECURITY_ATTRIBUTES security;
464 HANDLE in, out;
465 DWORD dwCreateFlags = 0;
466 BOOL res;
467 process_pair *proc;
468 char *cmd;
469 int i;
470 char *ptype = (char *)type;
471 HANDLE thread_token = NULL;
472 HANDLE token_user = NULL;
473 BOOL asuser = TRUE;
474
475 if (!type) {
476 return NULL;
477 }
478
479
480 type_len = strlen(type);
481 if (type_len <1 || type_len > 2) {
482 return NULL;
483 }
484
485 for (i=0; i < type_len; i++) {
486 if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) {
487 return NULL;
488 }
489 ptype++;
490 }
491
492 security.nLength = sizeof(SECURITY_ATTRIBUTES);
493 security.bInheritHandle = TRUE;
494 security.lpSecurityDescriptor = NULL;
495
496 if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
497 return NULL;
498 }
499
500 memset(&startup, 0, sizeof(STARTUPINFO));
501 memset(&process, 0, sizeof(PROCESS_INFORMATION));
502
503 startup.cb = sizeof(STARTUPINFO);
504 startup.dwFlags = STARTF_USESTDHANDLES;
505 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
506
507 read = (type[0] == 'r') ? TRUE : FALSE;
508 mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
509
510 if (read) {
511 in = dupHandle(in, FALSE);
512 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
513 startup.hStdOutput = out;
514 } else {
515 out = dupHandle(out, FALSE);
516 startup.hStdInput = in;
517 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
518 }
519
520 dwCreateFlags = NORMAL_PRIORITY_CLASS;
521 if (strcmp(sapi_module.name, "cli") != 0) {
522 dwCreateFlags |= CREATE_NO_WINDOW;
523 }
524
525
526 if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
527 DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
528 } else {
529 DWORD err = GetLastError();
530 if (err == ERROR_NO_TOKEN) {
531 asuser = FALSE;
532 }
533 }
534
535 cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
536 if (!cmd) {
537 return NULL;
538 }
539
540 sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
541 if (asuser) {
542 res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
543 CloseHandle(token_user);
544 } else {
545 res = CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
546 }
547 free(cmd);
548
549 if (!res) {
550 return NULL;
551 }
552
553 CloseHandle(process.hThread);
554 proc = process_get(NULL TSRMLS_CC);
555
556 if (read) {
557 fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
558 CloseHandle(out);
559 } else {
560 fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
561 CloseHandle(in);
562 }
563
564 stream = _fdopen(fno, type);
565 proc->prochnd = process.hProcess;
566 proc->stream = stream;
567 return stream;
568 }
569
570 TSRM_API int pclose(FILE *stream)
571 {
572 DWORD termstat = 0;
573 process_pair *process;
574 TSRMLS_FETCH();
575
576 if ((process = process_get(stream TSRMLS_CC)) == NULL) {
577 return 0;
578 }
579
580 fflush(process->stream);
581 fclose(process->stream);
582
583 WaitForSingleObject(process->prochnd, INFINITE);
584 GetExitCodeProcess(process->prochnd, &termstat);
585 process->stream = NULL;
586 CloseHandle(process->prochnd);
587
588 return termstat;
589 }
590
591 TSRM_API int shmget(int key, int size, int flags)
592 {
593 shm_pair *shm;
594 char shm_segment[26], shm_info[29];
595 HANDLE shm_handle, info_handle;
596 BOOL created = FALSE;
597
598 if (size < 0) {
599 return -1;
600 }
601
602 sprintf(shm_segment, "TSRM_SHM_SEGMENT:%d", key);
603 sprintf(shm_info, "TSRM_SHM_DESCRIPTOR:%d", key);
604
605 shm_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
606 info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info);
607
608 if ((!shm_handle && !info_handle)) {
609 if (flags & IPC_CREAT) {
610 shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, shm_segment);
611 info_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shm->descriptor), shm_info);
612 created = TRUE;
613 }
614 if ((!shm_handle || !info_handle)) {
615 return -1;
616 }
617 } else {
618 if (flags & IPC_EXCL) {
619 return -1;
620 }
621 }
622
623 shm = shm_get(key, NULL);
624 shm->segment = shm_handle;
625 shm->info = info_handle;
626 shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
627
628 if (NULL != shm->descriptor && created) {
629 shm->descriptor->shm_perm.key = key;
630 shm->descriptor->shm_segsz = size;
631 shm->descriptor->shm_ctime = time(NULL);
632 shm->descriptor->shm_cpid = getpid();
633 shm->descriptor->shm_perm.mode = flags;
634
635 shm->descriptor->shm_perm.cuid = shm->descriptor->shm_perm.cgid= 0;
636 shm->descriptor->shm_perm.gid = shm->descriptor->shm_perm.uid = 0;
637 shm->descriptor->shm_atime = shm->descriptor->shm_dtime = 0;
638 shm->descriptor->shm_lpid = shm->descriptor->shm_nattch = 0;
639 shm->descriptor->shm_perm.mode = shm->descriptor->shm_perm.seq = 0;
640 }
641
642 if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) {
643 if (NULL != shm->segment) {
644 CloseHandle(shm->segment);
645 }
646 UnmapViewOfFile(shm->descriptor);
647 CloseHandle(shm->info);
648 return -1;
649 }
650
651 return key;
652 }
653
654 TSRM_API void *shmat(int key, const void *shmaddr, int flags)
655 {
656 shm_pair *shm = shm_get(key, NULL);
657
658 if (!shm->segment) {
659 return (void*)-1;
660 }
661
662 shm->descriptor->shm_atime = time(NULL);
663 shm->descriptor->shm_lpid = getpid();
664 shm->descriptor->shm_nattch++;
665
666 shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
667
668 return shm->addr;
669 }
670
671 TSRM_API int shmdt(const void *shmaddr)
672 {
673 shm_pair *shm = shm_get(0, (void*)shmaddr);
674
675 if (!shm->segment) {
676 return -1;
677 }
678
679 shm->descriptor->shm_dtime = time(NULL);
680 shm->descriptor->shm_lpid = getpid();
681 shm->descriptor->shm_nattch--;
682
683 return UnmapViewOfFile(shm->addr) ? 0 : -1;
684 }
685
686 TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) {
687 shm_pair *shm = shm_get(key, NULL);
688
689 if (!shm->segment) {
690 return -1;
691 }
692
693 switch (cmd) {
694 case IPC_STAT:
695 memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
696 return 0;
697
698 case IPC_SET:
699 shm->descriptor->shm_ctime = time(NULL);
700 shm->descriptor->shm_perm.uid = buf->shm_perm.uid;
701 shm->descriptor->shm_perm.gid = buf->shm_perm.gid;
702 shm->descriptor->shm_perm.mode = buf->shm_perm.mode;
703 return 0;
704
705 case IPC_RMID:
706 if (shm->descriptor->shm_nattch < 1) {
707 shm->descriptor->shm_perm.key = -1;
708 }
709 return 0;
710
711 default:
712 return -1;
713 }
714 }
715
716 TSRM_API char *realpath(char *orig_path, char *buffer)
717 {
718 int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL);
719 if(!ret || ret > _MAX_PATH) {
720 return NULL;
721 }
722 return buffer;
723 }
724
725 #endif