int IOProxy::connect_callback( Stream * /*stream*/ ) { ReliSock *client = new ReliSock; bool accept_client = false; int success; success = server->accept(*client); if(success) { if(get_local_ipaddr().compare_address(client->peer_addr())) { dprintf(D_ALWAYS,"IOProxy: accepting connection from %s\n",client->peer_ip_str()); accept_client = true; } else { dprintf(D_ALWAYS,"IOProxy: rejecting connection from %s: invalid ip addr\n",client->peer_ip_str()); } } else { dprintf(D_ALWAYS,"IOProxy: Couldn't accept connection: %s\n",strerror(errno)); } if(accept_client) { IOProxyHandler *handler = new IOProxyHandler(); if(!handler->init(client,cookie)) { dprintf(D_ALWAYS,"IOProxy: couldn't register request callback!\n"); client->close(); delete client; } } else { client->close(); delete client; } return KEEP_STREAM; }
SharedPortState::HandlerResult SharedPortState::HandleFD(Stream *&s) { // Now send the fd. ReliSock *sock = static_cast<ReliSock *>(s); // The documented way to initialize msghdr is to first set msg_controllen // to the size of the cmsghdr buffer and then after initializing // cmsghdr(s) to set it to the sum of CMSG_LEN() across all cmsghdrs. struct msghdr msg; std::vector<char> buf; buf.reserve(CMSG_SPACE(sizeof(int))); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = &buf[0]; msg.msg_controllen = CMSG_SPACE(sizeof(int)); msg.msg_flags = 0; // I have found that on MacOS X 10.5, we must send at least 1 byte, // or we get "Message too long" when trying to send 0-byte message. struct iovec iov[1]; int junk = 0; iov[0].iov_base = &junk; iov[0].iov_len = 1; msg.msg_iov = iov; msg.msg_iovlen = 1; struct cmsghdr *cmsg = CMSG_FIRSTHDR((&msg)); void *cmsg_data = CMSG_DATA(cmsg); ASSERT( cmsg && cmsg_data ); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; int fd_to_pass = m_sock->get_file_desc(); memcpy(cmsg_data,&fd_to_pass,sizeof(int)); msg.msg_controllen = cmsg->cmsg_len; #ifdef USE_ABSTRACT_DOMAIN_SOCKET // // Even if we /can/ use abstract domain sockets, that doesn't meant that // we are. Check the socket's address; if the first byte of its "path" // is \0, it's an abstract socket, and we just pass the FD to it. // (See 'man 7 unix'). // // Otherwise, it's a socket on-disk; since those are potentially // less-secure (depending on filesystem permissions, which need to be lax // to permit HTCondor tools like ssh_to_job to work with daemons using // CCB), write an audit log entry about where the socket is going. // // In this construction, the non-error state is in the last if statement, // rather than the inner-most. // struct sockaddr_un addr; socklen_t addrlen = sizeof(struct sockaddr_un); if( -1 == getpeername( sock->get_file_desc(), (struct sockaddr *) & addr, & addrlen ) ) { dprintf( D_AUDIT, *sock, "Failure while auditing connection from %s: unable to obtain domain socket peer address: %s\n", m_sock->peer_addr().to_ip_and_port_string().c_str(), strerror( errno ) ); } else if( addrlen <= sizeof( sa_family_t ) ) { dprintf( D_AUDIT, *sock, "Failure while auditing connection from %s: unable to obtain domain socket peer address because domain socket peer is unnamed.\n", m_sock->peer_addr().to_ip_and_port_string().c_str() ); } else if( addr.sun_path[0] != '\0' ) { struct ucred cred; socklen_t len = sizeof(struct ucred); int rc = getsockopt( sock->get_file_desc(), SOL_SOCKET, SO_PEERCRED, & cred, & len ); if( rc == -1 ) { dprintf( D_AUDIT, *sock, "Failure while auditing connection via %s from %s: unable to obtain domain socket's peer credentials: %s.\n", addr.sun_path, m_sock->peer_addr().to_ip_and_port_string().c_str(), strerror( errno ) ); } else { std::string procPath; formatstr( procPath, "/proc/%d", cred.pid ); // Needs security review. char procExe[1025]; std::string procExePath = procPath + "/exe"; ssize_t procExeLength = readlink( procExePath.c_str(), procExe, 1024 ); if( procExeLength == -1 ) { strcpy( procExe, "(readlink failed)" ); } else if( 0 <= procExeLength && procExeLength <= 1024 ) { procExe[procExeLength] = '\0'; } else { procExe[1024] = '\0'; procExe[1023] = '.'; procExe[1022] = '.'; procExe[1021] = '.'; } // Needs security review. char procCmdLine[1025]; std::string procCmdLinePath = procPath + "/cmdline"; // No _follow, since the kernel doesn't create symlinks for this. int pclFD = safe_open_no_create( procCmdLinePath.c_str(), O_RDONLY ); ssize_t procCmdLineLength = _condor_full_read( pclFD, & procCmdLine, 1024 ); close( pclFD ); if( procCmdLineLength == -1 ) { strcpy( procCmdLine, "(unable to read cmdline)" ); } else if( 0 <= procCmdLineLength && procCmdLineLength <= 1024 ) { procCmdLine[procCmdLineLength] = '\0'; } else { procCmdLineLength = 1024; procCmdLine[1024] = '\0'; procCmdLine[1023] = '.'; procCmdLine[1022] = '.'; procCmdLine[1021] = '.'; } for( unsigned i = 0; i < procCmdLineLength; ++i ) { if( procCmdLine[i] == '\0' ) { if( procCmdLine[i+1] == '\0' ) { break; } procCmdLine[i] = ' '; } } // We can't use m_requested_by because it was supplied by the // remote process (and therefore can't be trusted). dprintf( D_AUDIT, *sock, "Forwarding connection to PID = %d, UID = %d, GID = %d [executable '%s'; command line '%s'] via %s from %s.\n", cred.pid, cred.uid, cred.gid, procExe, procCmdLine, addr.sun_path, m_sock->peer_addr().to_ip_and_port_string().c_str() ); } } #endif if( sendmsg(sock->get_file_desc(),&msg,0) != 1 ) { dprintf(D_ALWAYS,"SharedPortClient: failed to pass socket to %s%s: %s\n", m_sock_name.c_str(), m_requested_by.c_str(), strerror(errno)); return FAILED; } m_state = RECV_RESP; return WAIT; }