blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Quest Software, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Quest Software, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00040 // THIS CODE MUST NOT THROW EXCEPTIONS. IT IS ALSO HIGHLY PREFERRED THAT 00041 // IT NOT RELY ON ANY LIBRARY OTHER THAN STANDARD SYSTEM LIBRARIES AND THE 00042 // STANDARD C++ LIBRARY, AS IT IS USED IN libowcprivman, AND WE WANT TO AVOID 00043 // LINKING OTHER LIBRARIES IN WITH libowcprivman. 00044 00045 #include "blocxx/BLOCXX_config.h" 00046 #include "blocxx/DescriptorUtils_noexcept.hpp" 00047 #include "blocxx/AutoDescriptor.hpp" 00048 00049 #include <cstring> 00050 #include <sys/types.h> 00051 #ifdef BLOCXX_HAVE_SYS_SOCKET_H 00052 #include <sys/socket.h> 00053 #endif 00054 #ifndef BLOCXX_WIN32 00055 #include <sys/uio.h> 00056 #else 00057 #include "blocxx/WinProcessUtils.hpp" 00058 #endif 00059 00060 namespace BLOCXX_NAMESPACE 00061 { 00062 00063 namespace 00064 { 00065 char const MAGIC_CHAR = '\xa5'; 00066 00067 AutoDescriptor copy_error(char * dst, size_t dstsz, char const * src) 00068 { 00069 std::strncpy(dst, src, dstsz); 00070 dst[dstsz - 1] = '\0'; 00071 return AutoDescriptor(); 00072 } 00073 } 00074 00075 00076 #ifdef BLOCXX_WIN32 00077 00078 int passDescriptor(Descriptor streamPipe, Descriptor descriptor, ProcId targetProcessHd) 00079 { 00080 if (streamPipe == BLOCXX_INVALID_HANDLE) 00081 { 00082 return -1; 00083 } 00084 00085 DWORD targetProcessId = WinUtils::getProcessIdNT(targetProcessHd); 00086 00087 DWORD rc = -1; 00088 HANDLE dupDescriptor = INVALID_HANDLE_VALUE; 00089 HANDLE hProcess = targetProcessId == 0 ? GetCurrentProcess() : OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetProcessId); 00090 00091 BOOL fSuccess = DuplicateHandle(GetCurrentProcess(), descriptor, 00092 hProcess, &dupDescriptor, 0, 00093 FALSE, DUPLICATE_SAME_ACCESS); 00094 00095 CloseHandle(hProcess); 00096 00097 if (!fSuccess) 00098 { 00099 return -1; 00100 } 00101 00102 OVERLAPPED ovl; 00103 ZeroMemory(&ovl, sizeof(OVERLAPPED)); 00104 00105 fSuccess = WriteFile(streamPipe, &dupDescriptor, sizeof(long), &rc, &ovl); 00106 00107 if (!fSuccess) 00108 { 00109 DWORD lastError = GetLastError(); 00110 00111 if (lastError != ERROR_IO_INCOMPLETE && lastError != ERROR_IO_PENDING) 00112 { 00113 SetLastError(lastError); 00114 return -1; 00115 } 00116 else 00117 { 00118 DWORD waitFlag = WaitForSingleObject(streamPipe, INFINITE); 00119 00120 if (waitFlag == WAIT_OBJECT_0) 00121 { 00122 GetOverlappedResult(streamPipe, &ovl, &rc, FALSE); 00123 } 00124 else 00125 { 00126 return -1; 00127 } 00128 } 00129 } 00130 00131 return rc; 00132 } 00133 00134 AutoDescriptor receiveDescriptor(Descriptor streamPipe, char * errbuf, size_t bufsz) 00135 { 00136 long desc; 00137 DWORD rc = -1; 00138 BOOL bSuccess = FALSE; 00139 00140 if (streamPipe != BLOCXX_INVALID_HANDLE) 00141 { 00142 OVERLAPPED ovl; 00143 ZeroMemory(&ovl, sizeof(OVERLAPPED)); 00144 00145 bSuccess = ReadFile(streamPipe, &desc, sizeof(long), &rc, &ovl); 00146 00147 if (!bSuccess) 00148 { 00149 DWORD lastError = GetLastError(); 00150 00151 if (lastError != ERROR_IO_INCOMPLETE && lastError != ERROR_IO_PENDING) 00152 { 00153 SetLastError(lastError); 00154 return copy_error(errbuf, bufsz, "ReadFile() failed"); 00155 } 00156 else 00157 { 00158 DWORD waitFlag = WaitForSingleObject(streamPipe, INFINITE); 00159 00160 if (waitFlag == WAIT_OBJECT_0) 00161 { 00162 GetOverlappedResult(streamPipe, &ovl, &rc, FALSE); 00163 } 00164 else 00165 { 00166 return copy_error(errbuf, bufsz, "WaitForSingleObject() failed"); 00167 } 00168 } 00169 } 00170 00171 return AutoDescriptor(reinterpret_cast<HANDLE>(desc)); 00172 } 00173 00174 return copy_error(errbuf, bufsz, "receiveDescriptor() error"); 00175 } 00176 00177 #else 00178 00179 int passDescriptor(Descriptor streamPipe, Descriptor descriptor, ProcId targetProcessId) 00180 { 00181 struct msghdr msg; 00182 ::memset(&msg, 0, sizeof(msg)); 00183 struct iovec iov[1]; 00184 ::memset(iov, 0, sizeof(iov[0])); 00185 00186 #ifdef BLOCXX_HAVE_MSGHDR_MSG_CONTROL 00187 00188 // We need the newer CMSG_LEN() and CMSG_SPACE() macros, but few 00189 // implementations support them today. These two macros really need 00190 // an ALIGN() macro, but each implementation does this differently. 00191 #ifndef CMSG_LEN 00192 #define CMSG_LEN(size) (sizeof(struct cmsghdr) + (size)) 00193 #endif 00194 00195 #ifndef CMSG_SPACE 00196 #define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size)) 00197 #endif 00198 00199 union { 00200 struct cmsghdr cm; 00201 char control[CMSG_SPACE(sizeof(int))]; 00202 } control_un; 00203 ::memset(&control_un, 0, sizeof(control_un)); 00204 struct cmsghdr * cmptr; 00205 00206 msg.msg_control = control_un.control; 00207 msg.msg_controllen = sizeof(control_un.control); 00208 00209 cmptr = CMSG_FIRSTHDR(&msg); 00210 cmptr->cmsg_len = CMSG_LEN(sizeof(int)); 00211 cmptr->cmsg_level = SOL_SOCKET; 00212 cmptr->cmsg_type = SCM_RIGHTS; 00213 *(reinterpret_cast<int *>(CMSG_DATA(cmptr))) = descriptor; 00214 #else 00215 00216 #ifdef BLOCXX_NCR 00217 void *temp_cast = &descriptor; 00218 msg.msg_accrights = static_cast<caddr_t>(temp_cast); 00219 #else 00220 msg.msg_accrights = static_cast<caddr_t>(&descriptor); 00221 #endif 00222 00223 msg.msg_accrightslen = sizeof(int); 00224 #endif 00225 00226 msg.msg_name = 0; 00227 msg.msg_namelen = 0; 00228 00229 char dummy[1] = { MAGIC_CHAR }; 00230 iov[0].iov_base = dummy; 00231 iov[0].iov_len = 1; 00232 msg.msg_iov = iov; 00233 msg.msg_iovlen = 1; 00234 00235 return ::sendmsg(streamPipe, &msg, 0); 00236 } 00237 00238 AutoDescriptor receiveDescriptor(Descriptor streamPipe, char * errbuf, size_t bufsz) 00239 { 00240 struct msghdr msg; 00241 struct iovec iov[1]; 00242 00243 msg = msghdr(); // zero-init to make valgrind happy 00244 #ifdef BLOCXX_HAVE_MSGHDR_MSG_CONTROL 00245 union { 00246 struct cmsghdr cm; 00247 char control[CMSG_SPACE(sizeof(int))]; 00248 } control_un; 00249 00250 msg.msg_control = control_un.control; 00251 msg.msg_controllen = sizeof(control_un.control); 00252 #else 00253 int newfd = -1; 00254 00255 #ifdef BLOCXX_NCR 00256 void *temp_cast = &newfd; 00257 msg.msg_accrights = static_cast<caddr_t>(temp_cast); 00258 #else 00259 msg.msg_accrights = static_cast<caddr_t>(&newfd); 00260 #endif 00261 00262 msg.msg_accrightslen = sizeof(int); 00263 #endif 00264 00265 msg.msg_name = 0; 00266 msg.msg_namelen = 0; 00267 00268 char dummy[1] = { '\x7F' }; 00269 iov[0].iov_base = dummy; 00270 iov[0].iov_len = 1; 00271 msg.msg_iov = iov; 00272 msg.msg_iovlen = 1; 00273 00274 ssize_t n = ::recvmsg(streamPipe, &msg, 0); 00275 if (n == 0) 00276 { 00277 return copy_error(errbuf, bufsz, 00278 "unexpected end of input when receiving handle"); 00279 } 00280 if (n < 0) 00281 { 00282 return copy_error(errbuf, bufsz, "recvmsg() failed"); 00283 } 00284 if (n != 1) 00285 { 00286 return copy_error(errbuf, bufsz, "received more than 1 byte."); 00287 } 00288 if (dummy[0] != MAGIC_CHAR) 00289 { 00290 return copy_error(errbuf, bufsz, "bad magic char when receiving handle"); 00291 } 00292 00293 00294 #ifdef BLOCXX_HAVE_MSGHDR_MSG_CONTROL 00295 struct cmsghdr * cmptr = CMSG_FIRSTHDR(&msg); 00296 if (!cmptr) 00297 { 00298 return copy_error(errbuf, bufsz, 00299 "missing control message when receiving handle"); 00300 } 00301 // as far as I can tell, HP-UX is just broken and sets cmptr->cmsg_len to 12. Things work anyway. 00302 #if !defined (BLOCXX_HPUX) 00303 if (cmptr->cmsg_len != CMSG_LEN(sizeof(int))) 00304 { 00305 return copy_error(errbuf, bufsz, 00306 "cmptr->cmsg_len != CMSG_LEN(sizeof(int)) when receiving handle"); 00307 } 00308 #endif 00309 if (cmptr->cmsg_level != SOL_SOCKET) 00310 { 00311 return copy_error(errbuf, bufsz, 00312 "control level != SOL_SOCKET when receiving handle"); 00313 } 00314 if (cmptr->cmsg_type != SCM_RIGHTS) 00315 { 00316 return copy_error(errbuf, bufsz, 00317 "control type != SCM_RIGHTS when receiving handle"); 00318 } 00319 return AutoDescriptor(*(reinterpret_cast<int *>(CMSG_DATA(cmptr)))); 00320 #else 00321 if (msg.msg_accrightslen != sizeof(int)) 00322 { 00323 return copy_error(errbuf, bufsz, 00324 "bad control message when receiving handle"); 00325 } 00326 return AutoDescriptor(newfd); 00327 #endif 00328 } 00329 00330 #endif 00331 00332 00333 } // end namespace BLOCXX_NAMESPACE