1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sal.hxx" 26 27 #define UNICODE 28 #define _UNICODE 29 30 #ifndef WIN32_LEAN_AND_MEAN 31 # define WIN32_LEAN_AND_MEAN 32 # ifdef _MSC_VER 33 # pragma warning(push,1) /* disable warnings within system headers */ 34 # endif 35 # include <windows.h> 36 # ifdef _MSC_VER 37 # pragma warning(pop) 38 # endif 39 # include <tchar.h> 40 # undef WIN32_LEAN_AND_MEAN 41 #endif 42 #include "procimpl.h" 43 #include <rtl/ustring.hxx> 44 #include <rtl/ustrbuf.hxx> 45 #include "secimpl.h" 46 #include <osl/file.hxx> 47 48 #include <list> 49 #include <vector> 50 #include <algorithm> 51 #include <string> 52 53 //################################################# 54 extern "C" oslFileHandle SAL_CALL osl_createFileHandleFromOSHandle( HANDLE hFile, sal_uInt32 uFlags ); 55 56 //################################################# 57 const sal_Unicode NAME_VALUE_SEPARATOR = TEXT('='); 58 const sal_Char* SPACE = " "; 59 const rtl::OUString ENV_COMSPEC = rtl::OUString::createFromAscii("COMSPEC"); 60 const rtl::OUString QUOTE = rtl::OUString::createFromAscii("\""); 61 62 namespace /* private */ 63 { 64 //################################################# 65 typedef std::list<rtl::OUString> string_container_t; 66 typedef string_container_t::iterator string_container_iterator_t; 67 typedef string_container_t::const_iterator string_container_const_iterator_t; 68 typedef std::pair<string_container_iterator_t, string_container_iterator_t> iterator_pair_t; 69 typedef std::vector<sal_Unicode > environment_container_t; 70 71 //################################################# 72 /* Function object that compares two strings that are 73 expected to be environment variables in the form 74 "name=value". Only the 'name' part will be compared. 75 The comparison is in upper case and returns true 76 if the first of both strings is less than the 77 second one. */ 78 struct less_environment_variable : 79 public std::binary_function<rtl::OUString, rtl::OUString, bool> 80 { 81 bool operator() (const rtl::OUString& lhs, const rtl::OUString& rhs) const 82 { 83 OSL_ENSURE((lhs.indexOf(NAME_VALUE_SEPARATOR) > -1) && \ 84 (rhs.indexOf(NAME_VALUE_SEPARATOR) > -1), \ 85 "Malformed environment variable"); 86 87 // Windows compares environment variables uppercase 88 // so we do it, too 89 return (rtl_ustr_compare_WithLength( 90 lhs.toAsciiUpperCase().pData->buffer, 91 lhs.indexOf(NAME_VALUE_SEPARATOR), 92 rhs.toAsciiUpperCase().pData->buffer, 93 rhs.indexOf(NAME_VALUE_SEPARATOR)) < 0); 94 } 95 }; 96 97 //################################################# 98 /* Function object used by for_each algorithm to 99 calculate the sum of the length of all strings 100 in a string container. */ 101 class sum_of_string_lengths 102 { 103 public: 104 //-------------------------------- 105 sum_of_string_lengths() : sum_(0) {} 106 107 //-------------------------------- 108 void operator() (const rtl::OUString& string) 109 { 110 OSL_ASSERT(string.getLength()); 111 112 // always include the terminating '\0' 113 if (string.getLength()) 114 sum_ += string.getLength() + 1; 115 } 116 117 //-------------------------------- 118 operator size_t () const 119 { 120 return sum_; 121 } 122 private: 123 size_t sum_; 124 }; 125 126 //################################################# 127 inline size_t calc_sum_of_string_lengths(const string_container_t& string_cont) 128 { 129 return std::for_each( 130 string_cont.begin(), string_cont.end(), sum_of_string_lengths()); 131 } 132 133 //################################################# 134 void read_environment(/*out*/ string_container_t* environment) 135 { 136 // GetEnvironmentStrings returns a sorted list, Windows 137 // sorts environment variables upper case 138 LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings()); 139 LPTSTR p = env; 140 141 while (size_t l = _tcslen(p)) 142 { 143 environment->push_back(reinterpret_cast<const sal_Unicode*>(p)); 144 p += l + 1; 145 } 146 FreeEnvironmentStrings(env); 147 } 148 149 //################################################# 150 /* the environment list must be sorted, new values 151 should either replace existing ones or should be 152 added to the list, environment variables will 153 be handled case-insensitive */ 154 bool create_merged_environment( 155 rtl_uString* env_vars[], 156 sal_uInt32 env_vars_count, 157 /*in|out*/ string_container_t* merged_env) 158 { 159 OSL_ASSERT(env_vars && env_vars_count > 0 && merged_env); 160 161 read_environment(merged_env); 162 163 for (sal_uInt32 i = 0; i < env_vars_count; i++) 164 { 165 rtl::OUString env_var = rtl::OUString(env_vars[i]); 166 167 if (env_var.getLength() == 0) 168 return false; 169 170 iterator_pair_t iter_pair = std::equal_range( 171 merged_env->begin(), 172 merged_env->end(), 173 env_var, 174 less_environment_variable()); 175 176 if (env_var.indexOf(NAME_VALUE_SEPARATOR) == -1) 177 { 178 merged_env->erase(iter_pair.first, iter_pair.second); 179 } 180 else 181 { 182 if (iter_pair.first != iter_pair.second) // found 183 *iter_pair.first = env_var; 184 else // not found 185 merged_env->insert(iter_pair.first, env_var); 186 } 187 } 188 return true; 189 } 190 191 //################################################# 192 /* Create a merged environment */ 193 bool setup_process_environment( 194 rtl_uString* environment_vars[], 195 sal_uInt32 n_environment_vars, 196 /*in|out*/ environment_container_t& environment) 197 { 198 string_container_t merged_env; 199 if (!create_merged_environment(environment_vars, n_environment_vars, &merged_env)) 200 return false; 201 202 // allocate enough space for the '\0'-separated environment strings and 203 // a final '\0' 204 environment.resize(calc_sum_of_string_lengths(merged_env) + 1); 205 206 string_container_const_iterator_t iter = merged_env.begin(); 207 string_container_const_iterator_t iter_end = merged_env.end(); 208 209 sal_uInt32 pos = 0; 210 for (/**/; iter != iter_end; ++iter) 211 { 212 rtl::OUString envv = *iter; 213 214 OSL_ASSERT(envv.getLength()); 215 216 sal_uInt32 n = envv.getLength() + 1; // copy the final '\0', too 217 rtl_copyMemory( 218 reinterpret_cast<void*>(&environment[pos]), 219 reinterpret_cast<const void*>(envv.getStr()), 220 n * sizeof(sal_Unicode)); 221 pos += n; 222 } 223 environment[pos] = 0; // append a final '\0' 224 225 return true; 226 } 227 228 //########################################################## 229 /* In contrast to the Win32 API function CreatePipe with 230 this function the caller is able to determine separately 231 which handle of the pipe is inheritable. */ 232 bool create_pipe( 233 PHANDLE p_read_pipe, 234 bool b_read_pipe_inheritable, 235 PHANDLE p_write_pipe, 236 bool b_write_pipe_inheritable, 237 LPVOID p_security_descriptor = NULL, 238 DWORD pipe_size = 0) 239 { 240 SECURITY_ATTRIBUTES sa; 241 sa.nLength = sizeof(SECURITY_ATTRIBUTES); 242 sa.lpSecurityDescriptor = p_security_descriptor; 243 sa.bInheritHandle = b_read_pipe_inheritable || b_write_pipe_inheritable; 244 245 BOOL bRet = FALSE; 246 HANDLE hTemp = NULL; 247 248 if (!b_read_pipe_inheritable && b_write_pipe_inheritable) 249 { 250 bRet = CreatePipe(&hTemp, p_write_pipe, &sa, pipe_size); 251 252 if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp, 253 GetCurrentProcess(), p_read_pipe, 0, FALSE, 254 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) 255 { 256 CloseHandle(hTemp); 257 CloseHandle(*p_read_pipe); 258 return false; 259 } 260 } 261 else if (b_read_pipe_inheritable && !b_write_pipe_inheritable) 262 { 263 bRet = CreatePipe(p_read_pipe, &hTemp, &sa, pipe_size); 264 265 if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp, 266 GetCurrentProcess(), p_write_pipe, 0, FALSE, 267 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) 268 { 269 CloseHandle(hTemp); 270 CloseHandle(*p_write_pipe); 271 return false; 272 } 273 } 274 else 275 { 276 bRet = CreatePipe(p_read_pipe, p_write_pipe, &sa, pipe_size); 277 } 278 return bRet; 279 } 280 281 //######################################################### 282 // Add a quote sign to the start and the end of a string 283 // if not already present 284 rtl::OUString quote_string(const rtl::OUString& string) 285 { 286 rtl::OUStringBuffer quoted; 287 if (string.indexOf(QUOTE) != 0) 288 quoted.append(QUOTE); 289 290 quoted.append(string); 291 292 if (string.lastIndexOf(QUOTE) != (string.getLength() - 1)) 293 quoted.append(QUOTE); 294 295 return quoted.makeStringAndClear(); 296 } 297 298 //The parameter path must be a system path. If it is longer than 260 characters 299 //then it is shortened using the GetShortPathName function. This function only 300 //works if the path exists. Because "path" can be the path to an executable, it 301 //may not have the file extension ".exe". However, if the file on disk has the 302 //".exe" extension, then the function will fail. In this case a second attempt 303 //is started by adding the parameter "extension" to "path". 304 rtl::OUString getShortPath(rtl::OUString const & path, rtl::OUString const & extension) 305 { 306 rtl::OUString ret(path); 307 if (path.getLength() > 260) 308 { 309 std::vector<sal_Unicode> vec(path.getLength() + 1); 310 //GetShortPathNameW only works if the file can be found! 311 const DWORD len = GetShortPathNameW( 312 reinterpret_cast<LPCWSTR>(path.getStr()), reinterpret_cast<LPWSTR>(&vec[0]), path.getLength() + 1); 313 314 if (!len && GetLastError() == ERROR_FILE_NOT_FOUND 315 && extension.getLength()) 316 { 317 const rtl::OUString extPath(path + extension); 318 std::vector<sal_Unicode > vec2( extPath.getLength() + 1); 319 const DWORD len2 = GetShortPathNameW( 320 reinterpret_cast<LPCWSTR>(extPath.getStr()), reinterpret_cast<LPWSTR>(&vec2[0]), extPath.getLength() + 1); 321 ret = rtl::OUString(&vec2[0], len2); 322 } 323 else 324 { 325 ret = rtl::OUString(&vec[0], len); 326 } 327 } 328 return ret; 329 } 330 //########################################################## 331 // Returns the system path of the executable which can either 332 // be provided via the strImageName parameter or as first 333 // element of the strArguments list. 334 // The returned path will be quoted if it contains spaces. 335 rtl::OUString get_executable_path( 336 rtl_uString* image_name, 337 rtl_uString* cmdline_args[], 338 sal_uInt32 n_cmdline_args, 339 bool search_path) 340 { 341 rtl::OUString exe_name; 342 343 if (image_name) 344 exe_name = image_name; 345 else if (n_cmdline_args) 346 exe_name = rtl::OUString(cmdline_args[0]); 347 348 rtl::OUString exe_url = exe_name; 349 if (search_path) 350 osl_searchFileURL(exe_name.pData, NULL, &exe_url.pData); 351 352 rtl::OUString exe_path; 353 if (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(exe_url, exe_path)) 354 return rtl::OUString(); 355 356 exe_path = getShortPath(exe_path, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".exe"))); 357 358 if (exe_path.indexOf(' ') != -1) 359 exe_path = quote_string(exe_path); 360 361 return exe_path; 362 } 363 364 //########################################################## 365 rtl::OUString get_file_extension(const rtl::OUString& file_name) 366 { 367 sal_Int32 index = file_name.lastIndexOf('.'); 368 if ((index != -1) && ((index + 1) < file_name.getLength())) 369 return file_name.copy(index + 1); 370 371 return rtl::OUString(); 372 } 373 374 //########################################################## 375 bool is_batch_file(const rtl::OUString& file_name) 376 { 377 rtl::OUString ext = get_file_extension(file_name); 378 return (ext.equalsIgnoreAsciiCaseAscii("bat") || 379 ext.equalsIgnoreAsciiCaseAscii("cmd") || 380 ext.equalsIgnoreAsciiCaseAscii("btm")); 381 } 382 383 //########################################################## 384 rtl::OUString get_batch_processor() 385 { 386 rtl::OUString comspec; 387 osl_getEnvironment(ENV_COMSPEC.pData, &comspec.pData); 388 389 OSL_ASSERT(comspec.getLength()); 390 391 /* check if comspec path contains blanks and quote it if any */ 392 if (comspec.indexOf(' ') != -1) 393 comspec = quote_string(comspec); 394 395 return comspec; 396 } 397 398 } // namespace private 399 400 401 //################################################# 402 oslProcessError SAL_CALL osl_executeProcess( 403 rtl_uString *strImageName, 404 rtl_uString *strArguments[], 405 sal_uInt32 nArguments, 406 oslProcessOption Options, 407 oslSecurity Security, 408 rtl_uString *strDirectory, 409 rtl_uString *strEnvironmentVars[], 410 sal_uInt32 nEnvironmentVars, 411 oslProcess *pProcess 412 ) 413 { 414 return osl_executeProcess_WithRedirectedIO( 415 strImageName, 416 strArguments, 417 nArguments, 418 Options, 419 Security, 420 strDirectory, 421 strEnvironmentVars, 422 nEnvironmentVars, 423 pProcess, 424 NULL, NULL, NULL ); 425 } 426 427 //################################################# 428 oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO( 429 rtl_uString *ustrImageName, 430 rtl_uString *ustrArguments[], 431 sal_uInt32 nArguments, 432 oslProcessOption Options, 433 oslSecurity Security, 434 rtl_uString *ustrDirectory, 435 rtl_uString *ustrEnvironmentVars[], 436 sal_uInt32 nEnvironmentVars, 437 oslProcess *pProcess, 438 oslFileHandle *pProcessInputWrite, 439 oslFileHandle *pProcessOutputRead, 440 oslFileHandle *pProcessErrorRead) 441 { 442 rtl::OUString exe_path = get_executable_path( 443 ustrImageName, ustrArguments, nArguments, (Options & osl_Process_SEARCHPATH)); 444 445 if (0 == exe_path.getLength()) 446 return osl_Process_E_NotFound; 447 448 if (pProcess == NULL) 449 return osl_Process_E_InvalidError; 450 451 DWORD flags = NORMAL_PRIORITY_CLASS; 452 rtl::OUStringBuffer command_line; 453 454 if (is_batch_file(exe_path)) 455 { 456 rtl::OUString batch_processor = get_batch_processor(); 457 458 if (batch_processor.getLength()) 459 { 460 /* cmd.exe does not work without a console window */ 461 if (!(Options & osl_Process_WAIT) || (Options & osl_Process_DETACHED)) 462 flags |= CREATE_NEW_CONSOLE; 463 464 command_line.append(batch_processor); 465 command_line.appendAscii(" /c "); 466 } 467 else 468 // should we return here in case of error? 469 return osl_Process_E_Unknown; 470 } 471 472 command_line.append(exe_path); 473 474 /* Add remaining arguments to command line. If ustrImageName is NULL 475 the first parameter is the name of the executable so we have to 476 start at 1 instead of 0 */ 477 for (sal_uInt32 n = (NULL != ustrImageName) ? 0 : 1; n < nArguments; n++) 478 { 479 command_line.appendAscii(SPACE); 480 481 /* Quote arguments containing blanks */ 482 if (rtl::OUString(ustrArguments[n]).indexOf(' ') != -1) 483 command_line.append(quote_string(ustrArguments[n])); 484 else 485 command_line.append(ustrArguments[n]); 486 } 487 488 environment_container_t environment; 489 LPVOID p_environment = NULL; 490 491 if (nEnvironmentVars && ustrEnvironmentVars) 492 { 493 if (!setup_process_environment( 494 ustrEnvironmentVars, nEnvironmentVars, environment)) 495 return osl_Process_E_InvalidError; 496 497 flags |= CREATE_UNICODE_ENVIRONMENT; 498 p_environment = &environment[0]; 499 } 500 501 rtl::OUString cwd; 502 if (ustrDirectory && ustrDirectory->length && (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(ustrDirectory, cwd))) 503 return osl_Process_E_InvalidError; 504 505 LPCWSTR p_cwd = (cwd.getLength()) ? reinterpret_cast<LPCWSTR>(cwd.getStr()) : NULL; 506 507 if ((Options & osl_Process_DETACHED) && !(flags & CREATE_NEW_CONSOLE)) 508 flags |= DETACHED_PROCESS; 509 510 STARTUPINFO startup_info; 511 memset(&startup_info, 0, sizeof(STARTUPINFO)); 512 513 startup_info.cb = sizeof(STARTUPINFO); 514 startup_info.dwFlags = STARTF_USESHOWWINDOW; 515 startup_info.lpDesktop = L""; 516 517 /* Create pipes for redirected IO */ 518 HANDLE hInputRead = NULL; 519 HANDLE hInputWrite = NULL; 520 if (pProcessInputWrite && create_pipe(&hInputRead, true, &hInputWrite, false)) 521 startup_info.hStdInput = hInputRead; 522 523 HANDLE hOutputRead = NULL; 524 HANDLE hOutputWrite = NULL; 525 if (pProcessOutputRead && create_pipe(&hOutputRead, false, &hOutputWrite, true)) 526 startup_info.hStdOutput = hOutputWrite; 527 528 HANDLE hErrorRead = NULL; 529 HANDLE hErrorWrite = NULL; 530 if (pProcessErrorRead && create_pipe(&hErrorRead, false, &hErrorWrite, true)) 531 startup_info.hStdError = hErrorWrite; 532 533 bool b_inherit_handles = false; 534 if (pProcessInputWrite || pProcessOutputRead || pProcessErrorRead) 535 { 536 startup_info.dwFlags |= STARTF_USESTDHANDLES; 537 b_inherit_handles = true; 538 } 539 540 switch(Options & (osl_Process_NORMAL | osl_Process_HIDDEN | osl_Process_MINIMIZED | osl_Process_MAXIMIZED | osl_Process_FULLSCREEN)) 541 { 542 case osl_Process_HIDDEN: 543 startup_info.wShowWindow = SW_HIDE; 544 flags |= CREATE_NO_WINDOW; // ignored for non-console 545 // applications; ignored on 546 // Win9x 547 break; 548 549 case osl_Process_MINIMIZED: 550 startup_info.wShowWindow = SW_MINIMIZE; 551 break; 552 553 case osl_Process_MAXIMIZED: 554 case osl_Process_FULLSCREEN: 555 startup_info.wShowWindow = SW_MAXIMIZE; 556 break; 557 558 default: 559 startup_info.wShowWindow = SW_NORMAL; 560 } 561 562 rtl::OUString cmdline = command_line.makeStringAndClear(); 563 PROCESS_INFORMATION process_info; 564 BOOL bRet = FALSE; 565 566 if ((Security != NULL) && (((oslSecurityImpl*)Security)->m_hToken != NULL)) 567 { 568 bRet = CreateProcessAsUser( 569 ((oslSecurityImpl*)Security)->m_hToken, 570 NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL, 571 b_inherit_handles, flags, p_environment, p_cwd, 572 &startup_info, &process_info); 573 } 574 else 575 { 576 bRet = CreateProcess( 577 NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL, NULL, 578 b_inherit_handles, flags, p_environment, p_cwd, 579 &startup_info, &process_info); 580 } 581 582 /* Now we can close the pipe ends that are used by the child process */ 583 584 if (hInputRead) 585 CloseHandle(hInputRead); 586 587 if (hOutputWrite) 588 CloseHandle(hOutputWrite); 589 590 if (hErrorWrite) 591 CloseHandle(hErrorWrite); 592 593 if (bRet) 594 { 595 CloseHandle(process_info.hThread); 596 597 oslProcessImpl* pProcImpl = reinterpret_cast<oslProcessImpl*>( 598 rtl_allocateMemory(sizeof(oslProcessImpl))); 599 600 if (pProcImpl != NULL) 601 { 602 pProcImpl->m_hProcess = process_info.hProcess; 603 pProcImpl->m_IdProcess = process_info.dwProcessId; 604 605 *pProcess = (oslProcess)pProcImpl; 606 607 if (Options & osl_Process_WAIT) 608 WaitForSingleObject(pProcImpl->m_hProcess, INFINITE); 609 610 if (pProcessInputWrite) 611 *pProcessInputWrite = osl_createFileHandleFromOSHandle(hInputWrite, osl_File_OpenFlag_Write); 612 613 if (pProcessOutputRead) 614 *pProcessOutputRead = osl_createFileHandleFromOSHandle(hOutputRead, osl_File_OpenFlag_Read); 615 616 if (pProcessErrorRead) 617 *pProcessErrorRead = osl_createFileHandleFromOSHandle(hErrorRead, osl_File_OpenFlag_Read); 618 619 return osl_Process_E_None; 620 } 621 } 622 623 /* if an error occured we have to close the server side pipe ends too */ 624 625 if (hInputWrite) 626 CloseHandle(hInputWrite); 627 628 if (hOutputRead) 629 CloseHandle(hOutputRead); 630 631 if (hErrorRead) 632 CloseHandle(hErrorRead); 633 634 return osl_Process_E_Unknown; 635 } 636