static void do_client_cmd(UAContext *ua, CLIENTRES *client, const char *cmd) { BSOCK *fd; /* Connect to File daemon */ ua->jcr->res.client = client; /* Try to connect for 15 seconds */ ua->send_msg(_("Connecting to Client %s at %s:%d\n"), client->name(), client->address, client->FDport); if (!connect_to_file_daemon(ua->jcr, 1, 15, false, false)) { ua->error_msg(_("Failed to connect to Client.\n")); return; } Dmsg0(120, "Connected to file daemon\n"); fd = ua->jcr->file_bsock; fd->fsend("%s", cmd); if (fd->recv() >= 0) { ua->send_msg("%s", fd->msg); } fd->signal(BNET_TERMINATE); fd->close(); ua->jcr->file_bsock = NULL; return; }
/* * We get the number of drives in the changer from the SD */ int get_num_drives_from_SD(UAContext *ua) { STORERES *store = ua->jcr->res.wstore; char dev_name[MAX_NAME_LENGTH]; BSOCK *sd; int drives = 0; if (!(sd = open_sd_bsock(ua))) { return 0; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* * Ask for autochanger number of drives */ sd->fsend(changerdrivescmd, dev_name); while (sd->recv() >= 0) { if (sscanf(sd->msg, changerdrivesresponse, &drives) == 1) { break; } else { ua->send_msg("%s", sd->msg); } } close_sd_bsock(ua); // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives); return drives; }
static void do_storage_cmd(UAContext *ua, STORERES *store, const char *cmd) { BSOCK *sd; JCR *jcr = ua->jcr; USTORERES lstore; lstore.store = store; pm_strcpy(lstore.store_source, _("unknown source")); set_wstorage(jcr, &lstore); if (!(sd = open_sd_bsock(ua))) { ua->error_msg(_("Could not open SD socket.\n")); return; } Dmsg0(120, _("Connected to storage daemon\n")); sd = jcr->store_bsock; sd->fsend("%s", cmd); if (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); } close_sd_bsock(ua); return; }
static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive) { STORE *store = ua->jcr->wstore; BSOCK *sd; char dev_name[MAX_NAME_LENGTH]; char *VolName = NULL; int rtn_slot; if (!(sd=open_sd_bsock(ua))) { ua->error_msg(_("Could not open SD socket.\n")); return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* Ask for autochanger list of volumes */ sd->fsend(NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive); Dmsg1(100, "Sent: %s", sd->msg); /* Get Volume name in this Slot */ while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); Dmsg1(100, "Got: %s", sd->msg); if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) { VolName = (char *)malloc(sd->msglen); if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) { break; } free(VolName); VolName = NULL; } } close_sd_bsock(ua); Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName)); return VolName; }
/* * We get the number of slots in the changer from the SD */ static int get_num_slots_from_SD(UAContext *ua) { STORE *store = ua->jcr->wstore; char dev_name[MAX_NAME_LENGTH]; BSOCK *sd; int slots = 0; if (!(sd=open_sd_bsock(ua))) { return 0; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* Ask for autochanger number of slots */ sd->fsend(NT_("autochanger slots %s\n"), dev_name); while (sd->recv() >= 0) { if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) { break; } else { ua->send_msg("%s", sd->msg); } } close_sd_bsock(ua); ua->send_msg(_("Device \"%s\" has %d slots.\n"), store->dev_name(), slots); return slots; }
/* * Cancel a running job on a storage daemon. Used by the interactive cancel * command to cancel a JobId on a Storage Daemon this can be used when the * Director already removed the Job and thinks it finished but the Storage * Daemon still thinks its active. */ bool cancel_storage_daemon_job(UAContext *ua, STORERES *store, char *JobId) { BSOCK *sd; JCR *control_jcr; control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM); control_jcr->res.wstore = store; if (!connect_to_storage_daemon(control_jcr, 10, me->SDConnectTimeout, true)) { ua->error_msg(_("Failed to connect to Storage daemon.\n")); } Dmsg0(200, "Connected to storage daemon\n"); sd = control_jcr->store_bsock; sd->fsend("cancel Job=%s\n", JobId); while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); } sd->signal(BNET_TERMINATE); sd->close(); control_jcr->store_bsock = NULL; free_jcr(control_jcr); return true; }
/* * resolve a host on a storage daemon */ bool do_storage_resolve(UAContext *ua, STORERES *store) { BSOCK *sd; USTORERES lstore; lstore.store = store; pm_strcpy(lstore.store_source, _("unknown source")); set_wstorage(ua->jcr, &lstore); if (!(sd = open_sd_bsock(ua))) { return false; } for (int i = 1; i < ua->argc; i++) { if (!*ua->argk[i]) { continue; } sd->fsend("resolve %s", ua->argk[i]); while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); } } sd->signal(BNET_TERMINATE); sd->close(); ua->jcr->store_bsock = NULL; return true; }
/** * After writing a Volume, create the JobMedia record. */ bool SD_DCR::dir_create_jobmedia_record(bool zero) { BSOCK *dir = jcr->dir_bsock; char ed1[50]; /* * If system job, do not update catalog */ if (jcr->is_JobType(JT_SYSTEM)) { return true; } /* * Throw out records where FI is zero -- i.e. nothing done */ if (!zero && VolFirstIndex == 0 && (StartBlock != 0 || EndBlock != 0)) { Dmsg0(dbglvl, "JobMedia FI=0 StartBlock!=0 record suppressed\n"); return true; } if (!WroteVol) { return true; /* nothing written to tape */ } WroteVol = false; if (zero) { /* * Send dummy place holder to avoid purging */ dir->fsend(Create_job_media, jcr->Job, 0 , 0, 0, 0, 0, 0, 0, 0, edit_uint64(VolMediaId, ed1)); } else { dir->fsend(Create_job_media, jcr->Job, VolFirstIndex, VolLastIndex, StartFile, EndFile, StartBlock, EndBlock, Copy, Stripe, edit_uint64(VolMediaId, ed1)); } Dmsg1(dbglvl, ">dird %s", dir->msg); if (dir->recv() <= 0) { Dmsg0(dbglvl, "create_jobmedia error bnet_recv\n"); Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"), dir->bstrerror()); return false; } Dmsg1(dbglvl, "<dird %s", dir->msg); if (!bstrcmp(dir->msg, OK_create)) { Dmsg1(dbglvl, "Bad response from Dir: %s\n", dir->msg); Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg); return false; } return true; }
/* * Authenticate Director */ bool BSOCK::authenticate_with_director(JCR *jcr, const char *name, s_password &password, tls_t &tls, char *response, int response_len) { char bashed_name[MAX_NAME_LENGTH]; BSOCK *dir = this; /* for readability */ response[0] = 0; /* * Send my name to the Director then do authentication */ bstrncpy(bashed_name, name, sizeof(bashed_name)); bash_spaces(bashed_name); /* * Timeout Hello after 5 mins */ dir->start_timer(60 * 5); dir->fsend(hello, bashed_name); if (!authenticate_outbound_connection(jcr, "Director", name, password, tls)) { goto bail_out; } Dmsg1(6, ">dird: %s", dir->msg); if (dir->recv() <= 0) { dir->stop_timer(); bsnprintf(response, response_len, _("Bad response to Hello command: ERR=%s\n" "The Director at \"%s:%d\" is probably not running.\n"), dir->bstrerror(), dir->host(), dir->port()); return false; } dir->stop_timer(); Dmsg1(10, "<dird: %s", dir->msg); if (!bstrncmp(dir->msg, OKhello, sizeof(OKhello) - 1)) { bsnprintf(response, response_len, _("Director at \"%s:%d\" rejected Hello command\n"), dir->host(), dir->port()); return false; } else { bsnprintf(response, response_len, "%s", dir->msg); } return true; bail_out: dir->stop_timer(); bsnprintf(response, response_len, _("Authorization problem with Director at \"%s:%d\"\n" "Most likely the passwords do not agree.\n" "If you are using TLS, there may have been a certificate " "validation error during the TLS handshake.\n" "Please see %s for help.\n"), dir->host(), dir->port(), MANUAL_AUTH_URL); return false; }
/* * Now talk to the SD and do what he says */ static void do_sd_commands(JCR *jcr) { int i, status; bool found, quit; BSOCK *sd = jcr->store_bsock; sd->set_jcr(jcr); quit = false; while (!quit) { /* * Read command coming from the Storage daemon */ status = sd->recv(); if (is_bnet_stop(sd)) { /* hardeof or error */ break; /* connection terminated */ } if (status <= 0) { continue; /* ignore signals and zero length msgs */ } Dmsg1(110, "<stored: %s", sd->msg); found = false; for (i = 0; sd_cmds[i].cmd; i++) { if (bstrncmp(sd_cmds[i].cmd, sd->msg, strlen(sd_cmds[i].cmd))) { found = true; /* indicate command found */ jcr->errmsg[0] = 0; if (!sd_cmds[i].func(jcr)) { /* do command */ /* * Note sd->msg command may be destroyed by comm activity */ if (!job_canceled(jcr)) { if (jcr->errmsg[0]) { Jmsg1(jcr, M_FATAL, 0, _("Command error with SD, hanging up. %s\n"), jcr->errmsg); } else { Jmsg0(jcr, M_FATAL, 0, _("Command error with SD, hanging up.\n")); } jcr->setJobStatus(JS_ErrorTerminated); } quit = true; } break; } } if (!found) { /* command not found */ if (!job_canceled(jcr)) { Jmsg1(jcr, M_FATAL, 0, _("SD command not found: %s\n"), sd->msg); Dmsg1(110, "<stored: Command not found: %s\n", sd->msg); } sd->fsend(serrmsg); break; } } sd->signal(BNET_TERMINATE); /* signal to SD job is done */ }
/* * Now talk to the FD and do what he says */ void do_fd_commands(JCR *jcr) { int i; bool found, quit; BSOCK *fd = jcr->file_bsock; fd->set_jcr(jcr); for (quit=false; !quit;) { int status; /* Read command coming from the File daemon */ status = fd->recv(); if (is_bnet_stop(fd)) { /* hardeof or error */ break; /* connection terminated */ } if (status <= 0) { continue; /* ignore signals and zero length msgs */ } Dmsg1(110, "<filed: %s", fd->msg); found = false; for (i=0; fd_cmds[i].cmd; i++) { if (bstrncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd))) { found = true; /* indicate command found */ jcr->errmsg[0] = 0; if (!fd_cmds[i].func(jcr)) { /* do command */ /* Note fd->msg command may be destroyed by comm activity */ if (!job_canceled(jcr)) { if (jcr->errmsg[0]) { Jmsg1(jcr, M_FATAL, 0, _("Command error with FD, hanging up. %s\n"), jcr->errmsg); } else { Jmsg0(jcr, M_FATAL, 0, _("Command error with FD, hanging up.\n")); } jcr->setJobStatus(JS_ErrorTerminated); } quit = true; } break; } } if (!found) { /* command not found */ if (!job_canceled(jcr)) { Jmsg1(jcr, M_FATAL, 0, _("FD command not found: %s\n"), fd->msg); Dmsg1(110, "<filed: Command not found: %s\n", fd->msg); } fd->fsend(ferrmsg); break; } } fd->signal(BNET_TERMINATE); /* signal to FD job is done */ }
void cancel_storage_daemon_job(JCR *jcr) { if (jcr->sd_canceled) { return; /* cancel only once */ } UAContext *ua = new_ua_context(jcr); JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM); BSOCK *sd; ua->jcr = control_jcr; if (jcr->store_bsock) { if (!ua->jcr->wstorage) { if (jcr->rstorage) { copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource")); } else { copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource")); } } else { USTORE store; if (jcr->rstorage) { store.store = jcr->rstore; } else { store.store = jcr->wstore; } set_wstorage(ua->jcr, &store); } if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) { goto bail_out; } Dmsg0(200, "Connected to storage daemon\n"); sd = ua->jcr->store_bsock; sd->fsend("cancel Job=%s\n", jcr->Job); while (sd->recv() >= 0) { } sd->signal(BNET_TERMINATE); sd->close(); ua->jcr->store_bsock = NULL; jcr->sd_canceled = true; jcr->store_bsock->set_timed_out(); jcr->store_bsock->set_terminated(); sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL); jcr->my_thread_send_signal(TIMEOUT_SIGNAL); } bail_out: free_jcr(control_jcr); free_ua_context(ua); }
/* * Cancel a running job on a storage daemon. The silent flag sets * if we need to be silent or not e.g. when doing an interactive cancel * or a system invoked one. */ bool cancel_storage_daemon_job(UAContext *ua, JCR *jcr, bool silent) { BSOCK *sd; USTORERES store; if (!ua->jcr->wstorage) { if (jcr->rstorage) { copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource")); } else { copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource")); } } else { if (jcr->rstorage) { store.store = jcr->res.rstore; } else { store.store = jcr->res.wstore; } set_wstorage(ua->jcr, &store); } if (!connect_to_storage_daemon(ua->jcr, 10, me->SDConnectTimeout, true)) { if (!silent) { ua->error_msg(_("Failed to connect to Storage daemon.\n")); } return false; } Dmsg0(200, "Connected to storage daemon\n"); sd = ua->jcr->store_bsock; sd->fsend(canceljobcmd, jcr->Job); while (sd->recv() >= 0) { if (!silent) { ua->send_msg("%s", sd->msg); } } sd->signal(BNET_TERMINATE); sd->close(); delete ua->jcr->store_bsock; ua->jcr->store_bsock = NULL; if (silent) { jcr->sd_canceled = true; } jcr->store_bsock->set_timed_out(); jcr->store_bsock->set_terminated(); sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL); jcr->my_thread_send_signal(TIMEOUT_SIGNAL); return true; }
/* * Get the status of a remote storage daemon. */ void do_native_storage_status(UAContext *ua, STORERES *store, char *cmd) { BSOCK *sd; USTORERES lstore; lstore.store = store; pm_strcpy(lstore.store_source, _("unknown source")); set_wstorage(ua->jcr, &lstore); /* * Try connecting for up to 15 seconds */ if (!ua->api) { ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"), store->name(), store->address, store->SDport); } if (!connect_to_storage_daemon(ua->jcr, 10, me->SDConnectTimeout, false)) { ua->send_msg(_("\nFailed to connect to Storage daemon %s.\n====\n"), store->name()); if (ua->jcr->store_bsock) { ua->jcr->store_bsock->close(); delete ua->jcr->store_bsock; ua->jcr->store_bsock = NULL; } return; } Dmsg0(20, _("Connected to storage daemon\n")); sd = ua->jcr->store_bsock; if (cmd) { sd->fsend(dotstatuscmd, cmd); } else { sd->fsend(statuscmd); } while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); } sd->signal( BNET_TERMINATE); sd->close(); delete ua->jcr->store_bsock; ua->jcr->store_bsock = NULL; return; }
/* * Connection request. We accept connections either from the * Director, Storage Daemon or a Client (File daemon). * * Note, we are running as a seperate thread of the Storage daemon. * * Basic tasks done here: * - If it was a connection from the FD, call handle_filed_connection() * - If it was a connection from another SD, call handle_stored_connection() * - Otherwise it was a connection from the DIR, call handle_director_connection() */ static void *handle_connection_request(void *arg) { BSOCK *bs = (BSOCK *)arg; char name[MAX_NAME_LENGTH]; char tbuf[MAX_TIME_LENGTH]; if (bs->recv() <= 0) { Emsg1(M_ERROR, 0, _("Connection request from %s failed.\n"), bs->who()); bmicrosleep(5, 0); /* make user wait 5 seconds */ bs->close(); return NULL; } /* * Do a sanity check on the message received */ if (bs->msglen < MIN_MSG_LEN || bs->msglen > MAX_MSG_LEN) { Dmsg1(000, "<filed: %s", bs->msg); Emsg2(M_ERROR, 0, _("Invalid connection from %s. Len=%d\n"), bs->who(), bs->msglen); bmicrosleep(5, 0); /* make user wait 5 seconds */ bs->close(); return NULL; } Dmsg1(110, "Conn: %s", bs->msg); /* * See if this is a File daemon connection. If so call FD handler. */ if (sscanf(bs->msg, "Hello Start Job %127s", name) == 1) { Dmsg1(110, "Got a FD connection at %s\n", bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL))); return handle_filed_connection(bs, name); } /* * See if this is a Storage daemon connection. If so call SD handler. */ if (sscanf(bs->msg, "Hello Start Storage Job %127s", name) == 1) { Dmsg1(110, "Got a SD connection at %s\n", bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL))); return handle_stored_connection(bs, name); } Dmsg1(110, "Got a DIR connection at %s\n", bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL))); return handle_director_connection(bs); }
/* * Authenticate Director */ static int authenticate_director(JCR *jcr) { const MONITORRES *monitor = MonitorItemThread::instance()->getMonitor(); BSOCK *dir = jcr->dir_bsock; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; bool compatible = true; char bashed_name[MAX_NAME_LENGTH]; char *password; bstrncpy(bashed_name, monitor->hdr.name, sizeof(bashed_name)); bash_spaces(bashed_name); password = monitor->password; /* Timeout Hello after 5 mins */ btimer_t *tid = start_bsock_timer(dir, 60 * 5); dir->fsend(DIRhello, bashed_name); if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) || !cram_md5_challenge(dir, password, tls_local_need, compatible)) { stop_bsock_timer(tid); Jmsg1(jcr, M_FATAL, 0, _("Director authorization problem.\n" "Most likely the passwords do not agree.\n" "Please see %s for help.\n"), MANUAL_AUTH_URL); return 0; } Dmsg1(6, ">dird: %s", dir->msg); if (dir->recv() <= 0) { stop_bsock_timer(tid); Jmsg1(jcr, M_FATAL, 0, _("Bad response to Hello command: ERR=%s\n"), dir->bstrerror()); return 0; } Dmsg1(10, "<dird: %s", dir->msg); stop_bsock_timer(tid); if (strncmp(dir->msg, DIROKhello, sizeof(DIROKhello)-1) != 0) { Jmsg0(jcr, M_FATAL, 0, _("Director rejected Hello command\n")); return 0; } else { Jmsg0(jcr, M_INFO, 0, dir->msg); } return 1; }
/* * Authenticate File daemon connection */ static int authenticate_file_daemon(JCR *jcr, CLIENTRES* client) { const MONITORRES *monitor = MonitorItemThread::instance()->getMonitor(); BSOCK *fd = jcr->file_bsock; char dirname[MAX_NAME_LENGTH]; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; bool compatible = true; /* * Send my name to the File daemon then do authentication */ bstrncpy(dirname, monitor->hdr.name, sizeof(dirname)); bash_spaces(dirname); /* Timeout Hello after 5 mins */ btimer_t *tid = start_bsock_timer(fd, 60 * 5); if (!fd->fsend(SDFDhello, dirname)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to File daemon. ERR=%s\n"), bnet_strerror(fd)); return 0; } if (!cram_md5_respond(fd, client->password, &tls_remote_need, &compatible) || !cram_md5_challenge(fd, client->password, tls_local_need, compatible)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Director and File daemon passwords or names not the same.\n" "Please see " MANUAL_AUTH_URL " for help.\n")); return 0; } Dmsg1(116, ">filed: %s", fd->msg); if (fd->recv() <= 0) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Bad response from File daemon to Hello command: ERR=%s\n"), fd->bstrerror()); return 0; } Dmsg1(110, "<stored: %s", fd->msg); stop_bsock_timer(tid); if (strncmp(fd->msg, FDOKhello, sizeof(FDOKhello)-1) != 0) { Jmsg(jcr, M_FATAL, 0, _("File daemon rejected Hello command\n")); return 0; } return 1; }
/* * Authenticate Storage daemon connection */ int authenticate_storage_daemon(JCR *jcr, MONITOR *monitor, STORE* store) { BSOCK *sd = jcr->store_bsock; char dirname[MAX_NAME_LENGTH]; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; int compatible = true; /* * Send my name to the Storage daemon then do authentication */ bstrncpy(dirname, monitor->hdr.name, sizeof(dirname)); bash_spaces(dirname); /* Timeout Hello after 5 mins */ btimer_t *tid = start_bsock_timer(sd, 60 * 5); if (!sd->fsend(SDFDhello, dirname)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to Storage daemon. ERR=%s\n"), sd->bstrerror()); return 0; } if (!cram_md5_respond(sd, store->password, &tls_remote_need, &compatible) || !cram_md5_challenge(sd, store->password, tls_local_need, compatible)) { stop_bsock_timer(tid); Jmsg0(jcr, M_FATAL, 0, _("Director and Storage daemon passwords or names not the same.\n" "Please see " MANUAL_AUTH_URL " for help.\n")); return 0; } Dmsg1(116, ">stored: %s", sd->msg); if (sd->recv() <= 0) { stop_bsock_timer(tid); Jmsg1(jcr, M_FATAL, 0, _("bdird<stored: bad response to Hello command: ERR=%s\n"), sd->bstrerror()); return 0; } Dmsg1(110, "<stored: %s", sd->msg); stop_bsock_timer(tid); if (strncmp(sd->msg, SDOKhello, sizeof(SDOKhello)) != 0) { Jmsg0(jcr, M_FATAL, 0, _("Storage daemon rejected Hello command\n")); return 0; } return 1; }
/* * We get the volume name from the SD */ char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive) { BSOCK *sd; STORERES *store = ua->jcr->res.wstore; char dev_name[MAX_NAME_LENGTH]; char *VolName = NULL; int rtn_slot; if (!(sd = open_sd_bsock(ua))) { ua->error_msg(_("Could not open SD socket.\n")); return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* * Ask storage daemon to read the label of the volume in a * specific slot of the autochanger using the drive number given. * This could change the loaded volume in the drive. */ sd->fsend(readlabelcmd, dev_name, Slot, drive); Dmsg1(100, "Sent: %s", sd->msg); /* * Get Volume name in this Slot */ while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); Dmsg1(100, "Got: %s", sd->msg); if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) { VolName = (char *)malloc(sd->msglen); if (sscanf(sd->msg, readlabelresponse, VolName, &rtn_slot) == 2) { break; } free(VolName); VolName = NULL; } } close_sd_bsock(ua); Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName)); return VolName; }
/** * Common routine for: * dir_get_volume_info() * and * dir_find_next_appendable_volume() * * NOTE!!! All calls to this routine must be protected by * locking vol_info_mutex before calling it so that * we don't have one thread modifying the parameters * and another reading them. * * Returns: true on success and vol info in dcr->VolCatInfo * false on failure */ static bool do_get_volume_info(DCR *dcr) { JCR *jcr = dcr->jcr; BSOCK *dir = jcr->dir_bsock; VOLUME_CAT_INFO vol; int n; int32_t InChanger; dcr->setVolCatInfo(false); if (dir->recv() <= 0) { Dmsg0(dbglvl, "getvolname error bnet_recv\n"); Mmsg(jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n")); return false; } memset(&vol, 0, sizeof(vol)); Dmsg1(dbglvl, "<dird %s", dir->msg); n = sscanf(dir->msg, OK_media, vol.VolCatName, &vol.VolCatJobs, &vol.VolCatFiles, &vol.VolCatBlocks, &vol.VolCatBytes, &vol.VolCatMounts, &vol.VolCatErrors, &vol.VolCatWrites, &vol.VolCatMaxBytes, &vol.VolCatCapacityBytes, vol.VolCatStatus, &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles, &InChanger, &vol.VolReadTime, &vol.VolWriteTime, &vol.EndFile, &vol.EndBlock, &vol.LabelType, &vol.VolMediaId, vol.VolEncrKey, &vol.VolMinBlocksize, &vol.VolMaxBlocksize); if (n != 24) { Dmsg3(dbglvl, "Bad response from Dir fields=%d, len=%d: %s", n, dir->msglen, dir->msg); Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg); return false; } vol.InChanger = InChanger; /* bool in structure */ vol.is_valid = true; unbash_spaces(vol.VolCatName); bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName)); dcr->VolCatInfo = vol; /* structure assignment */ /* * If we received a new crypto key update the cache and write out the new cache on a change. */ if (*vol.VolEncrKey) { if (update_crypto_cache(vol.VolCatName, vol.VolEncrKey)) { write_crypto_cache(me->working_directory, "bareos-sd", get_first_port_host_order(me->SDaddrs)); } } Dmsg4(dbglvl, "do_get_volume_info return true slot=%d Volume=%s, " "VolminBlocksize=%u VolMaxBlocksize=%u\n", vol.Slot, vol.VolCatName, vol.VolMinBlocksize, vol.VolMaxBlocksize); Dmsg2(dbglvl, "setting dcr->VolMinBlocksize(%u) to vol.VolMinBlocksize(%u)\n", dcr->VolMinBlocksize, vol.VolMinBlocksize); Dmsg2(dbglvl, "setting dcr->VolMaxBlocksize(%u) to vol.VolMaxBlocksize(%u)\n", dcr->VolMaxBlocksize, vol.VolMaxBlocksize); /* * Assign the volcatinfo to the dcr. */ dcr->VolMinBlocksize = vol.VolMinBlocksize; dcr->VolMaxBlocksize = vol.VolMaxBlocksize; return true; }
/* * Handle Director User Agent commands */ static void *handle_UA_client_request(void *arg) { int status; UAContext *ua; JCR *jcr; BSOCK *user = (BSOCK *)arg; pthread_detach(pthread_self()); jcr = new_control_jcr("-Console-", JT_CONSOLE); ua = new_ua_context(jcr); ua->UA_sock = user; set_jcr_in_tsd(INVALID_JCR); user->recv(); /* Get first message */ if (!authenticate_user_agent(ua)) { goto getout; } while (!ua->quit) { if (ua->api) { user->signal(BNET_MAIN_PROMPT); } status = user->recv(); if (status >= 0) { pm_strcpy(ua->cmd, ua->UA_sock->msg); parse_ua_args(ua); if (ua->argc > 0 && ua->argk[0][0] == '.') { do_a_dot_command(ua); } else { do_a_command(ua); } dequeue_messages(ua->jcr); if (!ua->quit) { if (console_msg_pending && acl_access_ok(ua, Command_ACL, "messages")) { if (ua->auto_display_messages) { pm_strcpy(ua->cmd, "messages"); qmessages_cmd(ua, ua->cmd); ua->user_notified_msg_pending = false; } else if (!ua->gui && !ua->user_notified_msg_pending && console_msg_pending) { if (ua->api) { user->signal(BNET_MSGS_PENDING); } else { bsendmsg(ua, _("You have messages.\n")); } ua->user_notified_msg_pending = true; } } if (!ua->api) { user->signal(BNET_EOD); /* send end of command */ } } } else if (is_bnet_stop(user)) { ua->quit = true; } else { /* signal */ user->signal(BNET_POLL); } } getout: close_db(ua); free_ua_context(ua); free_jcr(jcr); user->close(); delete user; return NULL; }
bool run_cmd(JCR *jcr) { struct timeval tv; struct timezone tz; struct timespec timeout; int errstat = 0; BSOCK *cl; int fd_version = 0; int sd_version = 0; char job_name[500]; int i; int stat; Dsm_check(200); Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg); /* If we do not need the FD, we are doing a virtual backup. */ if (jcr->no_client_used()) { do_vbackup(jcr); return false; } jcr->sendJobStatus(JS_WaitFD); /* wait for FD to connect */ Dmsg2(050, "sd_calls_client=%d sd_client=%d\n", jcr->sd_calls_client, jcr->sd_client); if (jcr->sd_calls_client) { /* We connected to Client, so finish work */ cl = jcr->file_bsock; if (!cl) { Jmsg0(jcr, M_FATAL, 0, _("Client socket not open. Could not connect to Client.\n")); Dmsg0(050, "Client socket not open. Could not connect to Client.\n"); return false; } /* Get response to Hello command sent earlier */ Dmsg0(050, "Read Hello command from Client\n"); for (i=0; i<60; i++) { stat = cl->recv(); if (stat <= 0) { bmicrosleep(1, 0); } else { break; } } if (stat <= 0) { berrno be; Jmsg1(jcr, M_FATAL, 0, _("Recv request to Client failed. ERR=%s\n"), be.bstrerror()); Dmsg1(050, _("Recv request to Client failed. ERR=%s\n"), be.bstrerror()); return false; } Dmsg1(050, "Got from FD: %s\n", cl->msg); if (sscanf(cl->msg, "Hello Bacula SD: Start Job %127s %d %d", job_name, &fd_version, &sd_version) != 3) { Jmsg1(jcr, M_FATAL, 0, _("Bad Hello from Client: %s.\n"), cl->msg); Dmsg1(050, _("Bad Hello from Client: %s.\n"), cl->msg); return false; } unbash_spaces(job_name); jcr->FDVersion = fd_version; jcr->SDVersion = sd_version; Dmsg1(050, "FDVersion=%d\n", fd_version); /* * Authenticate the File daemon */ Dmsg0(050, "=== Authenticate FD\n"); if (jcr->authenticated || !authenticate_filed(jcr)) { Dmsg1(050, "Authentication failed Job %s\n", jcr->Job); Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n")); } else { jcr->authenticated = true; } } else if (!jcr->sd_client) { /* We wait to receive connection from Client */ gettimeofday(&tv, &tz); timeout.tv_nsec = tv.tv_usec * 1000; timeout.tv_sec = tv.tv_sec + me->client_wait; Dmsg3(050, "%s waiting %d sec for FD to contact SD key=%s\n", jcr->Job, (int)(timeout.tv_sec-time(NULL)), jcr->sd_auth_key); Dmsg3(800, "=== Block Job=%s jid=%d %p\n", jcr->Job, jcr->JobId, jcr); /* * Wait for the File daemon to contact us to start the Job, * when he does, we will be released, unless the 30 minutes * expires. */ P(mutex); while ( !jcr->authenticated && !job_canceled(jcr) ) { errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout); if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) { break; } Dmsg1(800, "=== Auth cond errstat=%d\n", errstat); } Dmsg4(050, "=== Auth=%d jid=%d canceled=%d errstat=%d\n", jcr->JobId, jcr->authenticated, job_canceled(jcr), errstat); V(mutex); Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr); } memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key)); if (jcr->authenticated && !job_canceled(jcr)) { Dmsg2(800, "Running jid=%d %p\n", jcr->JobId, jcr); run_job(jcr); /* Run the job */ } Dmsg2(800, "Done jid=%d %p\n", jcr->JobId, jcr); return false; }
/* * NOTE! This routine opens the SD socket but leaves it open */ static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, POOL_DBR *pr, int relabel, bool media_record_exists, int drive) { BSOCK *sd; char dev_name[MAX_NAME_LENGTH]; bool ok = false; bool is_dvd = false; uint64_t VolBytes = 0; if (!(sd=open_sd_bsock(ua))) { return false; } bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); bash_spaces(mr->VolumeName); bash_spaces(mr->MediaType); bash_spaces(pr->Name); if (relabel) { bash_spaces(omr->VolumeName); sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s " "MediaType=%s Slot=%d drive=%d", dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive); ua->send_msg(_("Sending relabel command from \"%s\" to \"%s\" ...\n"), omr->VolumeName, mr->VolumeName); } else { sd->fsend("label %s VolumeName=%s PoolName=%s MediaType=%s " "Slot=%d drive=%d", dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive); ua->send_msg(_("Sending label command for Volume \"%s\" Slot %d ...\n"), mr->VolumeName, mr->Slot); Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n", dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive); } while (sd->recv() >= 0) { int dvd; ua->send_msg("%s", sd->msg); if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes, &dvd) == 2) { is_dvd = dvd; ok = true; } } unbash_spaces(mr->VolumeName); unbash_spaces(mr->MediaType); unbash_spaces(pr->Name); mr->LabelDate = time(NULL); mr->set_label_date = true; if (is_dvd) { /* We know that a freshly labelled DVD has 1 VolParts */ /* This does not apply to auto-labelled DVDs. */ mr->VolParts = 1; } if (ok) { if (media_record_exists) { /* we update it */ mr->VolBytes = VolBytes; mr->InChanger = mr->Slot > 0; /* if slot give assume in changer */ mr->StorageId = ua->jcr->wstore->StorageId; if (!db_update_media_record(ua->jcr, ua->db, mr)) { ua->error_msg("%s", db_strerror(ua->db)); ok = false; } } else { /* create the media record */ set_pool_dbr_defaults_in_media_dbr(mr, pr); mr->VolBytes = VolBytes; mr->InChanger = mr->Slot > 0; /* if slot give assume in changer */ mr->StorageId = ua->jcr->wstore->StorageId; mr->Enabled = 1; if (db_create_media_record(ua->jcr, ua->db, mr)) { ua->info_msg(_("Catalog record for Volume \"%s\", Slot %d successfully created.\n"), mr->VolumeName, mr->Slot); /* Update number of volumes in pool */ pr->NumVols++; if (!db_update_pool_record(ua->jcr, ua->db, pr)) { ua->error_msg("%s", db_strerror(ua->db)); } } else { ua->error_msg("%s", db_strerror(ua->db)); ok = false; } } } else { ua->error_msg(_("Label command failed for Volume %s.\n"), mr->VolumeName); } return ok; }
bool MonitorItem::get_job_defaults(struct JobDefaults &job_defs) { int stat; char *def; BSOCK *dircomm; bool rtn = false; QString scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name); if (job_defs.job_name == "") { return rtn; } if (!doconnect()) { return rtn; } dircomm = d->DSock; dircomm->fsend("%s", scmd.toUtf8().data()); while ((stat = dircomm->recv()) > 0) { def = strchr(dircomm->msg, '='); if (!def) { continue; } /* Pointer to default value */ *def++ = 0; strip_trailing_newline(def); if (strcmp(dircomm->msg, "job") == 0) { if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) { goto bail_out; } continue; } if (strcmp(dircomm->msg, "pool") == 0) { job_defs.pool_name = def; continue; } if (strcmp(dircomm->msg, "messages") == 0) { job_defs.messages_name = def; continue; } if (strcmp(dircomm->msg, "client") == 0) { job_defs.client_name = def; continue; } if (strcmp(dircomm->msg, "storage") == 0) { job_defs.store_name = def; continue; } if (strcmp(dircomm->msg, "where") == 0) { job_defs.where = def; continue; } if (strcmp(dircomm->msg, "level") == 0) { job_defs.level = def; continue; } if (strcmp(dircomm->msg, "type") == 0) { job_defs.type = def; continue; } if (strcmp(dircomm->msg, "fileset") == 0) { job_defs.fileset_name = def; continue; } if (strcmp(dircomm->msg, "catalog") == 0) { job_defs.catalog_name = def; continue; } if (strcmp(dircomm->msg, "enabled") == 0) { job_defs.enabled = *def == '1' ? true : false; continue; } } rtn = true; /* Fall through wanted */ bail_out: return rtn; }
/* * Authenticate Director */ bool DirComm::authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons, char *errmsg, int errmsg_len) { BSOCK *dir = jcr->dir_bsock; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; bool tls_authenticate; int compatible = true; char bashed_name[MAX_NAME_LENGTH]; char *password; TLS_CONTEXT *tls_ctx = NULL; errmsg[0] = 0; /* * Send my name to the Director then do authentication */ if (cons) { bstrncpy(bashed_name, cons->hdr.name, sizeof(bashed_name)); bash_spaces(bashed_name); password = cons->password; /* TLS Requirement */ if (cons->tls_enable) { if (cons->tls_require) { tls_local_need = BNET_TLS_REQUIRED; } else { tls_local_need = BNET_TLS_OK; } } tls_authenticate = cons->tls_authenticate; tls_ctx = cons->tls_ctx; } else { bstrncpy(bashed_name, "*UserAgent*", sizeof(bashed_name)); password = director->password; /* TLS Requirement */ if (director->tls_enable) { if (director->tls_require) { tls_local_need = BNET_TLS_REQUIRED; } else { tls_local_need = BNET_TLS_OK; } } tls_authenticate = director->tls_authenticate; tls_ctx = director->tls_ctx; } if (tls_authenticate) { tls_local_need = BNET_TLS_REQUIRED; } /* Timeout Hello after 15 secs */ dir->start_timer(15); dir->fsend(hello, bashed_name); /* respond to Dir challenge */ if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) || /* Now challenge dir */ !cram_md5_challenge(dir, password, tls_local_need, compatible)) { bsnprintf(errmsg, errmsg_len, _("Director authorization problem at \"%s:%d\"\n"), dir->host(), dir->port()); goto bail_out; } /* Verify that the remote host is willing to meet our TLS requirements */ if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { bsnprintf(errmsg, errmsg_len, _("Authorization problem:" " Remote server at \"%s:%d\" did not advertise required TLS support.\n"), dir->host(), dir->port()); goto bail_out; } /* Verify that we are willing to meet the remote host's requirements */ if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { bsnprintf(errmsg, errmsg_len, _("Authorization problem with Director at \"%s:%d\":" " Remote server requires TLS.\n"), dir->host(), dir->port()); goto bail_out; } /* Is TLS Enabled? */ if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ if (!bnet_tls_client(tls_ctx, dir, NULL)) { bsnprintf(errmsg, errmsg_len, _("TLS negotiation failed with Director at \"%s:%d\"\n"), dir->host(), dir->port()); goto bail_out; } if (tls_authenticate) { /* authenticate only? */ dir->free_tls(); /* Yes, shutdown tls */ } } Dmsg1(6, ">dird: %s", dir->msg); if (dir->recv() <= 0) { dir->stop_timer(); bsnprintf(errmsg, errmsg_len, _("Bad response to Hello command: ERR=%s\n" "The Director at \"%s:%d\" is probably not running.\n"), dir->bstrerror(), dir->host(), dir->port()); return false; } dir->stop_timer(); Dmsg1(10, "<dird: %s", dir->msg); if (strncmp(dir->msg, OKhello, sizeof(OKhello)-1) != 0) { bsnprintf(errmsg, errmsg_len, _("Director at \"%s:%d\" rejected Hello command\n"), dir->host(), dir->port()); return false; } else { if (m_conn == 0) { bsnprintf(errmsg, errmsg_len, "%s", dir->msg); } } return true; bail_out: dir->stop_timer(); bsnprintf(errmsg, errmsg_len, _("Authorization problem with Director at \"%s:%d\"\n" "Most likely the passwords do not agree.\n" "If you are using TLS, there may have been a certificate validation error during the TLS handshake.\n" "Please see " MANUAL_AUTH_URL " for help.\n"), dir->host(), dir->port()); return false; }
/* * Authenticate Director */ int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) { BSOCK *dir = jcr->dir_bsock; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; bool tls_authenticate; int compatible = true; char bashed_name[MAX_NAME_LENGTH]; char *password; TLS_CONTEXT *tls_ctx = NULL; /* * Send my name to the Director then do authentication */ if (cons) { bstrncpy(bashed_name, cons->hdr.name, sizeof(bashed_name)); bash_spaces(bashed_name); password = cons->password; /* TLS Requirement */ if (cons->tls_enable) { if (cons->tls_require) { tls_local_need = BNET_TLS_REQUIRED; } else { tls_local_need = BNET_TLS_OK; } } if (cons->tls_authenticate) { tls_local_need = BNET_TLS_REQUIRED; } tls_authenticate = cons->tls_authenticate; tls_ctx = cons->tls_ctx; } else { bstrncpy(bashed_name, "*UserAgent*", sizeof(bashed_name)); password = director->password; /* TLS Requirement */ if (director->tls_enable) { if (director->tls_require) { tls_local_need = BNET_TLS_REQUIRED; } else { tls_local_need = BNET_TLS_OK; } } if (director->tls_authenticate) { tls_local_need = BNET_TLS_REQUIRED; } tls_authenticate = director->tls_authenticate; tls_ctx = director->tls_ctx; } /* Timeout Hello after 5 mins */ btimer_t *tid = start_bsock_timer(dir, 60 * 5); dir->fsend(hello, bashed_name); if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) || !cram_md5_challenge(dir, password, tls_local_need, compatible)) { goto bail_out; } /* Verify that the remote host is willing to meet our TLS requirements */ if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { sendit(_("Authorization problem:" " Remote server did not advertise required TLS support.\n")); goto bail_out; } /* Verify that we are willing to meet the remote host's requirements */ if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { sendit(_("Authorization problem:" " Remote server requires TLS.\n")); goto bail_out; } /* Is TLS Enabled? */ if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ if (!bnet_tls_client(tls_ctx, dir, NULL)) { sendit(_("TLS negotiation failed\n")); goto bail_out; } if (tls_authenticate) { /* Authenticate only? */ dir->free_tls(); /* yes, shutdown tls */ } } /* * It's possible that the TLS connection will * be dropped here if an invalid client certificate was presented */ Dmsg1(6, ">dird: %s", dir->msg); if (dir->recv() <= 0) { senditf(_("Bad response to Hello command: ERR=%s\n"), dir->bstrerror()); goto bail_out; } Dmsg1(10, "<dird: %s", dir->msg); if (strncmp(dir->msg, OKhello, sizeof(OKhello)-1) != 0) { sendit(_("Director rejected Hello command\n")); goto bail_out; } else { sendit(dir->msg); } stop_bsock_timer(tid); return 1; bail_out: stop_bsock_timer(tid); sendit( _("Director authorization problem.\n" "Most likely the passwords do not agree.\n" "If you are using TLS, there may have been a certificate validation error during the TLS handshake.\n" "Please see " MANUAL_AUTH_URL " for help.\n")); return 0; }
/* * Authenticate Storage daemon connection */ bool authenticate_storage_daemon(JCR *jcr, STORERES *store) { BSOCK *sd = jcr->store_bsock; char dirname[MAX_NAME_LENGTH]; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; int compatible = true; bool auth_success = false; /* * Send my name to the Storage daemon then do authentication */ bstrncpy(dirname, director->hdr.name, sizeof(dirname)); bash_spaces(dirname); /* Timeout Hello after 1 min */ btimer_t *tid = start_bsock_timer(sd, AUTH_TIMEOUT); if (!sd->fsend(hello, dirname)) { stop_bsock_timer(tid); Dmsg1(dbglvl, _("Error sending Hello to Storage daemon. ERR=%s\n"), bnet_strerror(sd)); Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to Storage daemon. ERR=%s\n"), bnet_strerror(sd)); return 0; } /* TLS Requirement */ if (store->tls_enable) { if (store->tls_require) { tls_local_need = BNET_TLS_REQUIRED; } else { tls_local_need = BNET_TLS_OK; } } if (store->tls_authenticate) { tls_local_need = BNET_TLS_REQUIRED; } auth_success = cram_md5_respond(sd, store->password, &tls_remote_need, &compatible); if (auth_success) { auth_success = cram_md5_challenge(sd, store->password, tls_local_need, compatible); if (!auth_success) { Dmsg1(dbglvl, "cram_challenge failed for %s\n", sd->who()); } } else { Dmsg1(dbglvl, "cram_respond failed for %s\n", sd->who()); } if (!auth_success) { stop_bsock_timer(tid); Dmsg0(dbglvl, _("Director and Storage daemon passwords or names not the same.\n")); Jmsg2(jcr, M_FATAL, 0, _("Director unable to authenticate with Storage daemon at \"%s:%d\". Possible causes:\n" "Passwords or names not the same or\n" "Maximum Concurrent Jobs exceeded on the SD or\n" "SD networking messed up (restart daemon).\n" "Please see " MANUAL_AUTH_URL " for help.\n"), sd->host(), sd->port()); return 0; } /* Verify that the remote host is willing to meet our TLS requirements */ if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not advertise required TLS support.\n")); return 0; } /* Verify that we are willing to meet the remote host's requirements */ if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n")); return 0; } /* Is TLS Enabled? */ if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ if (!bnet_tls_client(store->tls_ctx, sd, NULL)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with SD at \"%s:%d\"\n"), sd->host(), sd->port()); return 0; } if (store->tls_authenticate) { /* authentication only? */ sd->free_tls(); /* yes, stop tls */ } } Dmsg1(116, ">stored: %s", sd->msg); if (sd->recv() <= 0) { stop_bsock_timer(tid); Jmsg3(jcr, M_FATAL, 0, _("bdird<stored: \"%s:%s\" bad response to Hello command: ERR=%s\n"), sd->who(), sd->host(), sd->bstrerror()); return 0; } Dmsg1(110, "<stored: %s", sd->msg); stop_bsock_timer(tid); if (!bstrncmp(sd->msg, OKhello, sizeof(OKhello))) { Dmsg0(dbglvl, _("Storage daemon rejected Hello command\n")); Jmsg2(jcr, M_FATAL, 0, _("Storage daemon at \"%s:%d\" rejected Hello command\n"), sd->host(), sd->port()); return 0; } return 1; }
/* * Authenticate File daemon connection */ int authenticate_file_daemon(JCR *jcr) { BSOCK *fd = jcr->file_bsock; CLIENTRES *client = jcr->res.client; char dirname[MAX_NAME_LENGTH]; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; int compatible = true; bool auth_success = false; /* * Send my name to the File daemon then do authentication */ bstrncpy(dirname, director->name(), sizeof(dirname)); bash_spaces(dirname); /* Timeout Hello after 1 min */ btimer_t *tid = start_bsock_timer(fd, AUTH_TIMEOUT); if (!fd->fsend(hello, dirname)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to File daemon at \"%s:%d\". ERR=%s\n"), fd->host(), fd->port(), fd->bstrerror()); return 0; } Dmsg1(dbglvl, "Sent: %s", fd->msg); /* TLS Requirement */ if (client->tls_enable) { if (client->tls_require) { tls_local_need = BNET_TLS_REQUIRED; } else { tls_local_need = BNET_TLS_OK; } } if (client->tls_authenticate) { tls_local_need = BNET_TLS_REQUIRED; } auth_success = cram_md5_respond(fd, client->password, &tls_remote_need, &compatible); if (auth_success) { auth_success = cram_md5_challenge(fd, client->password, tls_local_need, compatible); if (!auth_success) { Dmsg1(dbglvl, "cram_auth failed for %s\n", fd->who()); } } else { Dmsg1(dbglvl, "cram_get_auth failed for %s\n", fd->who()); } if (!auth_success) { stop_bsock_timer(tid); Dmsg0(dbglvl, _("Director and File daemon passwords or names not the same.\n")); Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate with File daemon at \"%s:%d\". Possible causes:\n" "Passwords or names not the same or\n" "Maximum Concurrent Jobs exceeded on the FD or\n" "FD networking messed up (restart daemon).\n" "Please see " MANUAL_AUTH_URL " for help.\n"), fd->host(), fd->port()); return 0; } /* Verify that the remote host is willing to meet our TLS requirements */ if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Authorization problem: FD \"%s:%s\" did not advertise required TLS support.\n"), fd->who(), fd->host()); return 0; } /* Verify that we are willing to meet the remote host's requirements */ if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Authorization problem: FD at \"%s:%d\" requires TLS.\n"), fd->host(), fd->port()); return 0; } /* Is TLS Enabled? */ if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ if (!bnet_tls_client(client->tls_ctx, fd, client->tls_allowed_cns)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with FD at \"%s:%d\".\n"), fd->host(), fd->port()); return 0; } if (client->tls_authenticate) { /* tls authentication only? */ fd->free_tls(); /* yes, shutdown tls */ } } Dmsg1(116, ">filed: %s", fd->msg); if (fd->recv() <= 0) { stop_bsock_timer(tid); Dmsg1(dbglvl, _("Bad response from File daemon to Hello command: ERR=%s\n"), bnet_strerror(fd)); Jmsg(jcr, M_FATAL, 0, _("Bad response from File daemon at \"%s:%d\" to Hello command: ERR=%s\n"), fd->host(), fd->port(), fd->bstrerror()); return 0; } Dmsg1(110, "<filed: %s", fd->msg); stop_bsock_timer(tid); jcr->FDVersion = 0; if (!bstrncmp(fd->msg, FDOKhello, sizeof(FDOKhello)) && sscanf(fd->msg, FDOKnewHello, &jcr->FDVersion) != 1) { Dmsg0(dbglvl, _("File daemon rejected Hello command\n")); Jmsg(jcr, M_FATAL, 0, _("File daemon at \"%s:%d\" rejected Hello command\n"), fd->host(), fd->port()); return 0; } return 1; }