// 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; }
// 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; }
int store_cred_handler(Service * /*service*/, int /*i*/, Stream *stream) { void * data = NULL; int rtnVal = FALSE; int rc; char * temp_file_name = NULL; bool found_cred; CredentialWrapper * temp_cred = NULL; int data_size = -1; classad::ClassAd * _classad = NULL; classad::ClassAd classad; std::string classad_cstr; char * classad_str = NULL; classad::ClassAdParser parser; ReliSock * socket = (ReliSock*)stream; const char * user = NULL; CredentialWrapper * cred_wrapper = NULL; if (!socket->triedAuthentication()) { CondorError errstack; if( ! SecMan::authenticate_sock(socket, WRITE, &errstack) ) { dprintf (D_ALWAYS, "Unable to authenticate, qutting\n"); goto EXIT; } } user = socket->getFullyQualifiedUser(); dprintf (D_FULLDEBUG, "Request by: %s, %s\n", socket->getOwner(), user); socket->decode(); if (!socket->code (classad_str)) { dprintf (D_ALWAYS, "Error receiving credential metadata\n"); goto EXIT; } classad_cstr = classad_str; free (classad_str); _classad = parser.ParseClassAd(classad_cstr); if (!_classad) { dprintf (D_ALWAYS, "Error: invalid credential metadata %s\n", classad_cstr.c_str()); goto EXIT; } classad = *_classad; delete _classad; int type; if (!classad.EvaluateAttrInt ("Type", type)) { dprintf (D_ALWAYS, "Missing Type attribute in classad!\n"); goto EXIT; } if (type == X509_CREDENTIAL_TYPE) { cred_wrapper = new X509CredentialWrapper (classad); dprintf (D_ALWAYS, "Name=%s Size=%d\n", cred_wrapper->cred->GetName(), cred_wrapper->cred->GetDataSize()); } else { dprintf (D_ALWAYS, "Unsupported credential type %d\n", type); goto EXIT; } cred_wrapper->cred->SetOrigOwner (socket->getOwner()); // original remote uname cred_wrapper->cred->SetOwner (user); // mapped uname // Receive credential data data_size = cred_wrapper->cred->GetDataSize(); if (data_size > MAX_CRED_DATA_SIZE) { dprintf (D_ALWAYS, "ERROR: Credential data size %d > maximum allowed (%d)\n", data_size, MAX_CRED_DATA_SIZE); goto EXIT; } data = malloc (data_size); if (data == NULL) { EXCEPT("Out of memory. Aborting."); } if (!socket->code_bytes(data,data_size)) { dprintf (D_ALWAYS, "Error receiving credential data\n"); goto EXIT; } cred_wrapper->cred->SetData (data, data_size); // Check whether credential under this name already exists found_cred=false; credentials.Rewind(); while (credentials.Next(temp_cred)) { if ((strcmp(cred_wrapper->cred->GetName(), temp_cred->cred->GetName()) == 0) && (strcmp(cred_wrapper->cred->GetOwner(), temp_cred->cred->GetOwner()) == 0)) { found_cred=true; break; // found it } } if (found_cred) { dprintf (D_ALWAYS, "Credential %s for owner %s already exists!\n", cred_wrapper->cred->GetName(), cred_wrapper->cred->GetOwner()); socket->encode(); int rcred=CREDD_ERROR_CREDENTIAL_ALREADY_EXISTS; socket->code(rcred); goto EXIT; } // Write data to a file temp_file_name = dircat (cred_store_dir, "credXXXXXX"); condor_mkstemp (temp_file_name); cred_wrapper->SetStorageName (temp_file_name); init_user_id_from_FQN (user); if (!StoreData(temp_file_name,data,data_size)) { socket->encode(); int rcred = CREDD_UNABLE_TO_STORE; socket->code(rcred); goto EXIT; } ((X509CredentialWrapper*)cred_wrapper)->cred->SetRealExpirationTime ( x509_proxy_expiration_time(temp_file_name)); // Write metadata to a file credentials.Append (cred_wrapper); SaveCredentialList(); // Write response to the client socket->encode(); rc = CREDD_SUCCESS; socket->code(rc); dprintf( D_ALWAYS, "Credential name %s owner %s successfully stored\n", cred_wrapper->cred->GetName(), cred_wrapper->cred->GetOwner() ); if (type == X509_CREDENTIAL_TYPE) { ((X509Credential*)cred_wrapper->cred)->display( D_FULLDEBUG ); } rtnVal = TRUE; EXIT: if ( data != NULL ) { free (data); } if ( temp_file_name != NULL ) { delete [] temp_file_name; } if ( cred_wrapper != NULL) { delete cred_wrapper; } return rtnVal; }
int rm_cred_handler(Service * /*service*/, int /*i*/, Stream *stream) { char * name = NULL; int rtnVal = FALSE; int rc; bool found_cred; CredentialWrapper * cred_wrapper = NULL; char * owner = NULL; const char * user; ReliSock * socket = (ReliSock*)stream; if (!socket->triedAuthentication()) { CondorError errstack; if( ! SecMan::authenticate_sock(socket, READ, &errstack) ) { dprintf (D_ALWAYS, "Unable to authenticate, qutting\n"); goto EXIT; } } socket->decode(); if (!socket->code(name)) { dprintf (D_ALWAYS, "Error receiving credential name\n"); goto EXIT; } user = socket->getFullyQualifiedUser(); dprintf (D_ALWAYS, "Authenticated as %s\n", user); if (strchr (name, ':')) { // The name is of the form user:name // This better be a super-user! // TODO: Check super-user's list // Owner is the first part owner = strdup (name); char * pColon = strchr (owner, ':'); *pColon = '\0'; // Name is the second part sprintf (name, "%s", (char*)(pColon+sizeof(char))); if (strcmp (owner, user) != 0) { dprintf (D_ALWAYS, "Requesting another user's (%s) credential %s\n", owner, name); if (!isSuperUser (user)) { dprintf (D_ALWAYS, "User %s is NOT super user, request DENIED\n", user); goto EXIT; } else { dprintf (D_FULLDEBUG, "User %s is super user, request GRANTED\n", user); } } } else { owner = strdup (user); } dprintf (D_ALWAYS, "Attempting to delete cred %s for user %s\n", name, owner); found_cred=false; credentials.Rewind(); while (credentials.Next(cred_wrapper)) { if (cred_wrapper->cred->GetType() == X509_CREDENTIAL_TYPE) { if ((strcmp(cred_wrapper->cred->GetName(), name) == 0) && (strcmp(cred_wrapper->cred->GetOwner(), owner) == 0)) { credentials.DeleteCurrent(); found_cred=true; break; // found it } } } if (found_cred) { priv_state priv = set_root_priv(); // Remove credential data unlink (cred_wrapper->GetStorageName()); // Save the metadata list SaveCredentialList(); set_priv(priv); delete cred_wrapper; dprintf (D_ALWAYS, "Removed credential %s for owner %s\n", name, owner); } else { dprintf (D_ALWAYS, "Unable to remove credential %s:%s (not found)\n", owner, name); } free (owner); socket->encode(); rc = (found_cred)?CREDD_SUCCESS:CREDD_CREDENTIAL_NOT_FOUND; socket->code(rc); rtnVal = TRUE; EXIT: if (name != NULL) { free (name); } return rtnVal; }
int query_cred_handler(Service * /*service*/, int /*i*/, Stream *stream) { classad::ClassAdUnParser unparser; std::string adbuffer; char * request = NULL; int rtnVal = FALSE; int length; CredentialWrapper * cred = NULL; SimpleList <Credential*> result_list; ReliSock * socket = (ReliSock*)stream; const char * user; if (!socket->triedAuthentication()) { CondorError errstack; if( ! SecMan::authenticate_sock(socket, READ, &errstack) ) { dprintf (D_ALWAYS, "Unable to authenticate, qutting\n"); goto EXIT; } } user = socket->getFullyQualifiedUser(); dprintf (D_ALWAYS, "Authenticated as %s\n", user); socket->decode(); if (!socket->code(request)) { dprintf (D_ALWAYS, "Error receiving request\n"); goto EXIT; } if ((request != NULL) && (strcmp (request, "*") == 0)) { if (!isSuperUser (user)) { dprintf (D_ALWAYS, "User %s is NOT super user, request DENIED\n", user); goto EXIT; } } // Find credentials for this user credentials.Rewind(); while (credentials.Next(cred)) { if (cred->cred->GetType() == X509_CREDENTIAL_TYPE) { if (strcmp(cred->cred->GetOwner(), user) == 0) { result_list.Append (cred->cred); } } } socket->encode(); length = result_list.Length(); dprintf (D_FULLDEBUG, "User has %d credentials\n", length); socket->code (length); Credential * _cred; result_list.Rewind(); while (result_list.Next(_cred)) { classad::ClassAd * _temp = cred->GetMetadata(); unparser.Unparse(adbuffer,_temp); char * classad_str = strdup(adbuffer.c_str()); socket->code (classad_str); free (classad_str); delete _temp; } rtnVal = TRUE; EXIT: if (request != NULL) { free (request); } return rtnVal; }
int get_cred_handler(Service * /*service*/, int /*i*/, Stream *stream) { char * name = NULL; int rtnVal = FALSE; bool found_cred=false; CredentialWrapper * cred = NULL; char * owner = NULL; const char * user = NULL; void * data = NULL; ReliSock * socket = (ReliSock*)stream; // Authenticate if (!socket->triedAuthentication()) { CondorError errstack; if( ! SecMan::authenticate_sock(socket, READ, &errstack) ) { dprintf (D_ALWAYS, "Unable to authenticate, qutting\n"); goto EXIT; } } socket->decode(); if (!socket->code(name)) { dprintf (D_ALWAYS, "Error receiving credential name\n"); goto EXIT; } user = socket->getFullyQualifiedUser(); dprintf (D_ALWAYS, "Authenticated as %s\n", user); if (strchr (name, ':')) { // The name is of the form user:name // This better be a super-user! // TODO: Check super-user's list // Owner is the first part owner = strdup (name); char * pColon = strchr (owner, ':'); *pColon = '\0'; // Name is the second part sprintf (name, "%s", (char*)(pColon+sizeof(char))); if (strcmp (owner, user) != 0) { dprintf (D_ALWAYS, "Requesting another user's (%s) credential %s\n", owner, name); if (!isSuperUser (user)) { dprintf (D_ALWAYS, "User %s is NOT super user, request DENIED\n", user); goto EXIT; } else { dprintf (D_FULLDEBUG, "User %s is super user, request GRANTED\n", user); } } } else { owner = strdup (user); } dprintf (D_ALWAYS, "sending cred %s for user %s\n", name, owner); credentials.Rewind(); while (credentials.Next(cred)) { if (cred->cred->GetType() == X509_CREDENTIAL_TYPE) { if ((strcmp(cred->cred->GetName(), name) == 0) && (strcmp(cred->cred->GetOwner(), owner) == 0)) { found_cred=true; break; // found it } } } socket->encode(); if (found_cred) { dprintf (D_FULLDEBUG, "Found cred %s\n", cred->GetStorageName()); int data_size; int rc = LoadData (cred->GetStorageName(), data, data_size); dprintf (D_FULLDEBUG, "Credential::LoadData returned %d\n", rc); if (rc == 0) { goto EXIT; } socket->code (data_size); socket->code_bytes (data, data_size); dprintf (D_ALWAYS, "Credential name %s for owner %s returned to user %s\n", name, owner, user); } else { dprintf (D_ALWAYS, "Cannot find cred %s\n", name); int rc = CREDD_CREDENTIAL_NOT_FOUND; socket->code (rc); } rtnVal = TRUE; EXIT: if ( name != NULL) { free (name); } if ( owner != NULL) { free (owner); } if ( data != NULL) { free (data); } return rtnVal; }