예제 #1
0
// Called when the schedd initially connects to the transferd to finish
// the registration process.
int
TransferD::setup_transfer_request_handler(int  /*cmd*/, Stream *sock)
{
	ReliSock *rsock = (ReliSock*)sock;
	MyString sock_id;

	dprintf(D_ALWAYS, "Got TRANSFER_CONTROL_CHANNEL!\n");

	rsock->decode();

	///////////////////////////////////////////////////////////////
	// make sure we are authenticated
	///////////////////////////////////////////////////////////////
	if( ! rsock->triedAuthentication() ) {
		CondorError errstack;
		if( ! SecMan::authenticate_sock(rsock, WRITE, &errstack) ) {
			// we failed to authenticate, we should bail out now
			// since we don't know what user is trying to perform
			// this action.
			// TODO: it'd be nice to print out what failed, but we
			// need better error propagation for that...
			errstack.push( "TransferD::setup_transfer_request_handler()", 42,
				"Failure to register transferd - Authentication failed" );
			dprintf( D_ALWAYS, "setup_transfer_request_handler() "
				"aborting: %s\n",
				errstack.getFullText().c_str() );
			refuse(rsock);
			return CLOSE_STREAM;
		} 
	}

	rsock->decode();

	///////////////////////////////////////////////////////////////
	// Register this socket with a socket handler to handle incoming requests
	///////////////////////////////////////////////////////////////

	sock_id += "<TreqChannel-Socket>";

	char* _sock_id = strdup( sock_id.Value() );		//de-const

	// register the handler for any future transfer requests on this socket.
	daemonCore->Register_Socket((Sock*)rsock, _sock_id,
		(SocketHandlercpp)&TransferD::accept_transfer_request_handler,
		"TransferD::accept_transfer_request_handler", this, ALLOW);
	
	free( _sock_id );
	
	dprintf(D_ALWAYS, "Treq channel established.\n");
	dprintf(D_ALWAYS, "Accepting Transfer Requests.\n");

	return KEEP_STREAM;
}
예제 #2
0
// This handler is called when a client wishes to write files from the
// transferd's storage.
int
TransferD::write_files_handler(int cmd, Stream *sock) 
{
	ReliSock *rsock = (ReliSock*)sock;
	MyString capability;
	int protocol = FTP_UNKNOWN;
	TransferRequest *treq = NULL;
	MyString fquser;
	static int transfer_reaper_id = -1;
	ThreadArg *thread_arg;
	int tid;
	ClassAd reqad;
	ClassAd respad;

	cmd = cmd; // quiet the compiler.

	dprintf(D_ALWAYS, "Got TRANSFERD_WRITE_FILES!\n");

	/////////////////////////////////////////////////////////////////////////
	// make sure we are authenticated
	/////////////////////////////////////////////////////////////////////////
	if( ! rsock->triedAuthentication() ) {
		CondorError errstack;
		if( ! SecMan::authenticate_sock(rsock, WRITE, &errstack) ) {
			// we failed to authenticate, we should bail out now
			// since we don't know what user is trying to perform
			// this action.
			// TODO: it'd be nice to print out what failed, but we
			// need better error propagation for that...
			errstack.push( "TransferD::setup_transfer_request_handler()", 42,
				"Failure to register transferd - Authentication failed" );
			dprintf( D_ALWAYS, "setup_transfer_request_handler() "
				"aborting: %s\n",
				errstack.getFullText() );
			refuse( rsock );
			return CLOSE_STREAM;
		} 
	}

	fquser = rsock->getFullyQualifiedUser();


	/////////////////////////////////////////////////////////////////////////
	// Check to see if the capability the client tells us is something that
	// we have knowledge of. We ONLY check the capability and not the
	// identity of the person in question. This allows people of different
	// identities to write files here as long as they had the right 
	// capability. While this might not sound secure, they STILL had to have
	// authenticated as someone this daemon trusts. 
	// Similarly, check the protocol it wants to use as well as ensure that
	// the direction the transfer request was supposed to be is being honored.
	/////////////////////////////////////////////////////////////////////////
	rsock->decode();

	// soak the request ad from the client about what it wants to transfer
	reqad.initFromStream(*rsock);
	rsock->end_of_message();

	reqad.LookupString(ATTR_TREQ_CAPABILITY, capability);

	rsock->encode();

	// do I know of such a capability?
	if (m_treqs.lookup(capability, treq) != 0) {
		// didn't find it. Log it and tell them to leave and close up shop
		respad.Assign(ATTR_TREQ_INVALID_REQUEST, TRUE);
		respad.Assign(ATTR_TREQ_INVALID_REASON, "Invalid capability!");
		respad.put(*rsock);
		rsock->end_of_message();

		dprintf(D_ALWAYS, "Client identity '%s' tried to write some files "
			"using capability '%s', but there was no such capability. "
			"Access denied.\n", fquser.Value(), capability.Value());
		return CLOSE_STREAM;
	}

	reqad.LookupInteger(ATTR_TREQ_FTP, protocol);

	// am I willing to use this protocol?
	switch(protocol) {
		case FTP_CFTP: // FileTrans protocol, I'm happy.
			break;

		default:
			respad.Assign(ATTR_TREQ_INVALID_REQUEST, TRUE);
			respad.Assign(ATTR_TREQ_INVALID_REASON, 
				"Invalid file transfer protocol!");
			respad.put(*rsock);
			rsock->end_of_message();

			dprintf(D_ALWAYS, "Client identity '%s' tried to write some files "
				"using protocol '%d', but I don't support that protocol. "
				"Access denied.\n", fquser.Value(), protocol);
			return CLOSE_STREAM;
	}

	// nsure that this transfer request was of the uploading variety
	if (treq->get_direction() != FTPD_UPLOAD) {
			respad.Assign(ATTR_TREQ_INVALID_REQUEST, TRUE);
			respad.Assign(ATTR_TREQ_INVALID_REASON, 
				"Transfer Request was not an uploading request!");
			respad.put(*rsock);
			rsock->end_of_message();

			dprintf(D_ALWAYS, "Client identity '%s' tried to write some files "
				"to a transfer request that wasn't expecting to be written. "
				"Access denied.\n", fquser.Value());
	}

	/////////////////////////////////////////////////////////////////////////
	// Tell the client everything was ok.
	/////////////////////////////////////////////////////////////////////////

	respad.Assign(ATTR_TREQ_INVALID_REQUEST, FALSE);
	respad.put(*rsock);
	rsock->end_of_message();

	/////////////////////////////////////////////////////////////////////////
	// Set up a thread (a process under unix) to read ALL of the job files
	// for all of the ads in the TransferRequest.
	/////////////////////////////////////////////////////////////////////////

	// now create a thread, passing in the sock, which uses the file transfer
	// object to accept the files.

	if (transfer_reaper_id == -1) {
		// only set this up ONCE so each and every thread gets one.
		transfer_reaper_id = daemonCore->Register_Reaper(
						"write_files_reaper",
						(ReaperHandlercpp) &TransferD::write_files_reaper,
						"write_files_reaper",
						this
						);
	}

	thread_arg = new ThreadArg(protocol, treq);

	// Start a new thread (process on Unix) to do the work
	tid = daemonCore->Create_Thread(
		(ThreadStartFunc)&TransferD::write_files_thread,
		(void *)thread_arg,
		rsock,
		transfer_reaper_id
		);
	
	if (tid == FALSE) {
		// XXX How do I handle this failure?
	}


	// associate the tid with the request so I can deal with it propery in
	// the reaper
	m_client_to_transferd_threads.insert(tid, treq);

	// The stream is inherited to the thread, who does the transfer and
	// finishes the protocol, but in the parent, I'm closing it.
	return CLOSE_STREAM;
}
예제 #3
0
// Note: logfile is not passed as a reference because we need a local
// copy to modify anyhow.
bool
ReadMultipleUserLogs::monitorLogFile( MyString logfile,
			bool truncateIfFirst, CondorError &errstack )
{
	dprintf( D_LOG_FILES, "ReadMultipleUserLogs::monitorLogFile(%s, %d)\n",
				logfile.Value(), truncateIfFirst );

	MyString fileID;
	if ( !GetFileID( logfile, fileID, errstack ) ) {
		errstack.push( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
					"Error getting file ID in monitorLogFile()" );
		return false;
	}

	LogFileMonitor *monitor;
	if ( allLogFiles.lookup( fileID, monitor ) == 0 ) {
		dprintf( D_LOG_FILES, "ReadMultipleUserLogs: found "
					"LogFileMonitor object for %s (%s)\n",
					logfile.Value(), fileID.Value() );

	} else {
		dprintf( D_LOG_FILES, "ReadMultipleUserLogs: didn't "
					"find LogFileMonitor object for %s (%s)\n",
					logfile.Value(), fileID.Value() );

			// Make sure the log file is in the correct state -- it must
			// exist, and be truncated if necessary.
		if ( !MultiLogFiles::InitializeFile( logfile.Value(),
					truncateIfFirst, errstack ) ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error initializing log file %s", logfile.Value() );
			return false;
		}

		monitor = new LogFileMonitor( logfile );
		ASSERT( monitor );
		dprintf( D_LOG_FILES, "ReadMultipleUserLogs: created LogFileMonitor "
					"object for log file %s\n", logfile.Value() );
			// Note: we're only putting a pointer to the LogFileMonitor
			// object into the hash table; the actual LogFileMonitor should
			// only be deleted in this object's destructor.
		if ( allLogFiles.insert( fileID, monitor ) != 0 ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error inserting %s into allLogFiles",
						logfile.Value() );
			delete monitor;
			return false;
		}
	}

	if ( monitor->refCount < 1 ) {
			// Open the log file (return to previous location if it was
			// opened before).
	
		if ( monitor->state ) {
				// If we get here, we've monitored this log file before,
				// so restore the previous state.
			if ( monitor->stateError ) {
				errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
							"Monitoring log file %s fails because of "
							"previous error saving file state",
							logfile.Value() );
				return false;
			}

			monitor->readUserLog = new ReadUserLog( *(monitor->state) );
		} else {
				// Monitoring this log file for the first time, so create
				// the log reader from scratch.
			monitor->readUserLog =
						new ReadUserLog( monitor->logFile.Value() );
		}

		if ( activeLogFiles.insert( fileID, monitor ) != 0 ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error inserting %s (%s) into activeLogFiles",
						logfile.Value(), fileID.Value() );
			return false;
		} else {
			dprintf( D_LOG_FILES, "ReadMultipleUserLogs: added log "
						"file %s (%s) to active list\n", logfile.Value(),
						fileID.Value() );
		}
	}

	monitor->refCount++;
	
	return true;
}
예제 #4
0
// Note: logfile is not passed as a reference because we need a local
// copy to modify anyhow.
bool
ReadMultipleUserLogs::unmonitorLogFile( MyString logfile,
			CondorError &errstack )
{
	dprintf( D_LOG_FILES, "ReadMultipleUserLogs::unmonitorLogFile(%s)\n",
				logfile.Value() );

	MyString fileID;
	if ( !GetFileID( logfile, fileID, errstack ) ) {
		errstack.push( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
					"Error getting file ID in unmonitorLogFile()" );
		return false;
	}

	LogFileMonitor *monitor;
	if ( activeLogFiles.lookup( fileID, monitor ) != 0 ) {
		errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
					"Didn't find LogFileMonitor object for log "
					"file %s (%s)!", logfile.Value(),
					fileID.Value() );
		dprintf( D_ALWAYS, "ReadMultipleUserLogs error: %s\n",
					errstack.message() );
		printAllLogMonitors( NULL );
		return false;
	}

	dprintf( D_LOG_FILES, "ReadMultipleUserLogs: found "
				"LogFileMonitor object for %s (%s)\n",
				logfile.Value(), fileID.Value() );

	monitor->refCount--;

	if ( monitor->refCount < 1 ) {
			// Okay, if we are no longer monitoring this file at all,
			// we need to close it.  We do that by saving its state
			// into a ReadUserLog::FileState object (so we can go back
			// to the right place if we later monitor it again) and
			// then deleting the ReadUserLog object.
		dprintf( D_LOG_FILES, "Closing file <%s>\n", logfile.Value() );

		if ( !monitor->state ) {
			monitor->state = new ReadUserLog::FileState();
			if ( !ReadUserLog::InitFileState( *(monitor->state) ) ) {
				errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
							"Unable to initialize ReadUserLog::FileState "
							"object for log file %s", logfile.Value() );
				monitor->stateError = true;
				delete monitor->state;
				monitor->state = NULL;
				return false;
			}
		}

		if ( !monitor->readUserLog->GetFileState( *(monitor->state) ) ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error getting state for log file %s",
						logfile.Value() );
			monitor->stateError = true;
			delete monitor->state;
			monitor->state = NULL;
			return false;
		}

		delete monitor->readUserLog;
		monitor->readUserLog = NULL;

			// Now we remove this file from the "active" list, so
			// we don't check it the next time we get an event.
		if ( activeLogFiles.remove( fileID ) != 0 ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error removing %s (%s) from activeLogFiles",
						logfile.Value(), fileID.Value() );
			dprintf( D_ALWAYS, "ReadMultipleUserLogs error: %s\n",
						errstack.message() );
			printAllLogMonitors( NULL );
			return false;
		}

		dprintf( D_LOG_FILES, "ReadMultipleUserLogs: removed "
					"log file %s (%s) from active list\n",
					logfile.Value(), fileID.Value() );
	}

	return true;
}