FileRecord *Dir_resolve_file(Dir *dir, bstring path) { FileRecord *file = NULL; bstring target = NULL; check(Dir_lazy_normalize_base(dir) == 0, "Failed to normalize base path when requesting %s", bdata(path)); check(bstrncmp(path, dir->prefix, blength(dir->prefix)) == 0, "Request for path %s does not start with %s prefix.", bdata(path), bdata(dir->prefix)); file = FileRecord_cache_check(dir, path); if(file) { // TODO: double check this gives the right users count file->users++; return file; } // We subtract one from the blengths below, because dir->prefix includes // a trailing '/'. If we skip over this in path->data, we drop the '/' // from the URI, breaking the target path if(bchar(path, blength(path) - 1) == '/') { target = bformat("%s%s%s", bdata(dir->normalized_base), path->data + blength(dir->prefix) - 1, bdata(dir->index_file)); } else { target = bformat("%s%s", bdata(dir->normalized_base), path->data + blength(dir->prefix) - 1); } check(target, "Couldn't construct target path for %s", bdata(path)); check_debug(normalize_path(target) == 0, "Failed to normalize target path."); check_debug(bstrncmp(target, dir->normalized_base, blength(dir->normalized_base)) == 0, "Request for path %s does not start with %s base after normalizing.", bdata(target), bdata(dir->base)); // the FileRecord now owns the target file = Dir_find_file(target, dir->default_ctype); check_debug(file, "Error opening file: %s", bdata(target)); // Increment the user count because we're adding it to the cache file->users++; file->request_path = bstrcpy(path); Cache_add(dir->fr_cache, file); return file; error: bdestroy(target); FileRecord_release(file); return NULL; }
/* * See in the tree with selected files what files were selected to be restored. */ static inline int set_files_to_restore(JCR *jcr, struct ndm_job_param *job, int32_t FileIndex, const char *restore_prefix, const char *ndmp_filesystem) { int len; int cnt = 0; TREE_NODE *node, *parent; POOL_MEM restore_pathname, tmp; node = first_tree_node(jcr->restore_tree_root); while (node) { /* * See if this is the wanted FileIndex and the user asked to extract it. */ if (node->FileIndex == FileIndex && node->extract) { pm_strcpy(restore_pathname, node->fname); /* * Walk up the parent until we hit the head of the list. */ for (parent = node->parent; parent; parent = parent->parent) { pm_strcpy(tmp, restore_pathname.c_str()); Mmsg(restore_pathname, "%s/%s", parent->fname, tmp.c_str()); } /* * We only want to restore the non pseudo NDMP names e.g. not the full backup stream name. */ if (!bstrncmp(restore_pathname.c_str(), "/@NDMP/", 7)) { /* * See if we need to strip the prefix from the filename. */ len = strlen(ndmp_filesystem); if (bstrncmp(restore_pathname.c_str(), ndmp_filesystem, len)) { add_to_namelist(job, restore_pathname.c_str() + len, restore_prefix, (char *)"", (char *)"", NDMP_INVALID_U_QUAD); } else { add_to_namelist(job, restore_pathname.c_str(), restore_prefix, (char *)"", (char *)"", NDMP_INVALID_U_QUAD); } cnt++; } } node = next_tree_node(node); } return cnt; }
/* * Check if this is a cleaning tape by comparing the Volume name * with the Cleaning Prefix. If they match, this is a cleaning * tape. */ static inline bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr) { bool retval; /* * Find Pool resource */ ua->jcr->res.pool = (POOLRES *)GetResWithName(R_POOL, pr->Name); if (!ua->jcr->res.pool) { ua->error_msg(_("Pool \"%s\" resource not found for volume \"%s\"!\n"), pr->Name, mr->VolumeName); return false; } retval = bstrncmp(mr->VolumeName, ua->jcr->res.pool->cleaning_prefix, strlen(ua->jcr->res.pool->cleaning_prefix)); Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d bstrncmp=%s\n", ua->jcr->res.pool->cleaning_prefix, mr->VolumeName, strlen(ua->jcr->res.pool->cleaning_prefix), retval ? "true" : "false"); return retval; }
/* * Walk the tree of selected files for restore and lookup the * correct fileid. Return the actual full pathname of the file * corresponding to the given fileid. */ static inline char *lookup_fileindex(JCR *jcr, int32_t FileIndex) { TREE_NODE *node, *parent; POOL_MEM restore_pathname, tmp; node = first_tree_node(jcr->restore_tree_root); while (node) { /* * See if this is the wanted FileIndex. */ if (node->FileIndex == FileIndex) { pm_strcpy(restore_pathname, node->fname); /* * Walk up the parent until we hit the head of the list. */ for (parent = node->parent; parent; parent = parent->parent) { pm_strcpy(tmp, restore_pathname.c_str()); Mmsg(restore_pathname, "%s/%s", parent->fname, tmp.c_str()); } if (bstrncmp(restore_pathname.c_str(), "/@NDMP/", 7)) { return bstrdup(restore_pathname.c_str()); } } node = next_tree_node(node); } return NULL; }
/* * Search the table of built-in variables, and if found, * call the appropriate subroutine to do the work. */ static var_rc_t lookup_built_in_var(var_t *ctx, void *my_ctx, const char *var_ptr, int var_len, int var_index, const char **val_ptr, int *val_len, int *val_size) { JCR *jcr = (JCR *)my_ctx; int status, i; for (i = 0; _(built_in_vars[i].var_name); i++) { if (bstrncmp(_(built_in_vars[i].var_name), var_ptr, var_len)) { status = (*built_in_vars[i].func)(jcr, built_in_vars[i].code, val_ptr, val_len, val_size); if (status) { return VAR_OK; } break; } } return VAR_ERR_UNDEFINED_VARIABLE; }
static s32 binaryFind(LTable* lt, const char* hash) { u32 start = 0; u32 end = lt->n_rows-1; while (start != end) { u32 middle = (start + end) / 2; if (bstrncmp(hash, CHASH(middle), lt->l_hash) <= 0) end = middle; else start = middle + 1; } if (bstrncmp(CHASH(start), hash, lt->l_hash) == 0) return start; else return -1; }
static int parse_bind_address(allium_ptcfg *cfg, const char *addrs) { struct bstrList *l; struct tagbstring str; int i, j; assert(NULL != cfg); if (NULL == addrs) { fprintf(stdout, "ENV-ERROR No Bind Addresses\n"); return (-1); } btfromcstr(str, addrs); if (0 == btlength(str)) { fprintf(stdout, "ENV-ERROR Empty Bind Address\n"); return (-1); } l = bsplit(&str, ','); if (NULL == l) { fprintf(stdout, "ENV-ERROR OOM parsing Bind Addresses\n"); return (-1); } if (l->qty != cfg->nr_methods) { fprintf(stdout, "ENV-ERROR Malformed Bind Addresses\n"); bstrListDestroy(l); return (-1); } for (i = 0; i < l->qty; i++) { /* * Per pt-spec.txt, the order is identical to the transport * list. I have no idea what is supposed to happen when * the transport list is wildcarded, so this routine will * currently fail gracefully. */ j = bstrrchr(l->entry[i], '-'); if ((j != blength(cfg->methods[i].name)) || bstrncmp(l->entry[i], cfg->methods[i].name, j - 1)) { fprintf(stdout, "ENV-ERROR Unexpected method in Bind Address\n"); bstrListDestroy(l); return (-1); } cfg->methods[i].bind_addr_len = sizeof(cfg->methods[i].bind_addr); if (parse_addr(bdataofs(l->entry[i], j + 1), (struct sockaddr *)&cfg->methods[i].bind_addr, &cfg->methods[i].bind_addr_len)) { fprintf(stdout, "ENV-ERROR Invalid address in Bind Address (%s)\n", bdata(l->entry[i])); bstrListDestroy(l); return (-1); } cfg->methods[i].has_bind_addr = 1; } bstrListDestroy(l); return (0); }
/* * 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 */ }
/* * Called here to do a special operation on a variable * op_ptr points to the special operation code (not EOS terminated) * arg_ptr points to argument to special op code * val_ptr points to the value string * out_ptr points to string to be returned */ static var_rc_t operate_var(var_t *var, void *my_ctx, const char *op_ptr, int op_len, const char *arg_ptr, int arg_len, const char *val_ptr, int val_len, char **out_ptr, int *out_len, int *out_size) { COUNTERRES *counter; POOL_MEM buf(PM_NAME); var_rc_t status = VAR_ERR_UNDEFINED_OPERATION; Dmsg0(100, "Enter operate_var\n"); if (!val_ptr) { *out_size = 0; return status; } if (op_len == 3 && bstrncmp(op_ptr, "inc", 3)) { buf.check_size(val_len + 1); pm_memcpy(buf, arg_ptr, val_len); (buf.c_str())[val_len] = 0; Dmsg1(100, "Arg=%s\n", buf.c_str()); pm_memcpy(buf, val_ptr, val_len); (buf.c_str())[val_len] = 0; Dmsg1(100, "Val=%s\n", buf.c_str()); LockRes(); for (counter = NULL; (counter = (COUNTERRES *)GetNextRes(R_COUNTER, (RES *)counter)); ) { if (bstrcmp(counter->name(), buf.c_str())) { Dmsg2(100, "counter=%s val=%s\n", counter->name(), buf.c_str()); break; } } UnlockRes(); return status; } *out_size = 0; return status; }
static void quicksort(LTable* lt, u32 left, u32 right) { if (left >= right) return; swap(lt, (left+right)/2, right); char* pivotValue = CHASH(right); u32 storeIndex = left; for (u32 i = left; i < right; i++) if (bstrncmp(CHASH(i), pivotValue, lt->l_hash) < 0) swap(lt, i, storeIndex++); swap(lt, storeIndex, right); if (storeIndex) quicksort(lt, left, storeIndex-1); quicksort(lt, storeIndex+1, right); }
/* * Do a relative cwd -- i.e. relative to current node rather than root node */ TREE_NODE *tree_relcwd(char *path, TREE_ROOT *root, TREE_NODE *node) { char *p; int len; TREE_NODE *cd; char save_char; int match; if (*path == 0) { return node; } /* * Check the current segment only */ if ((p = first_path_separator(path)) != NULL) { len = p - path; } else { len = strlen(path); } Dmsg2(100, "tree_relcwd: len=%d path=%s\n", len, path); foreach_child(cd, node) { Dmsg1(100, "tree_relcwd: test cd=%s\n", cd->fname); if (cd->fname[0] == path[0] && len == (int)strlen(cd->fname) && bstrncmp(cd->fname, path, len)) { break; } /* * fnmatch has no len in call so we truncate the string */ save_char = path[len]; path[len] = 0; match = fnmatch(path, cd->fname, 0) == 0; path[len] = save_char; if (match) { break; } }
/* * Given a Job, find the JCR compares on the number of * characters in Job thus allowing partial matches. * * Returns: jcr on success * NULL on failure */ JCR *get_jcr_by_partial_name(char *Job) { JCR *jcr; int len; if (!Job) { return NULL; } len = strlen(Job); foreach_jcr(jcr) { if (bstrncmp(Job, jcr->Job, len)) { jcr->inc_use_count(); Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n", jcr->JobId, jcr->use_count(), jcr->Job); break; } } endeach_jcr(jcr); return jcr; }
/* Generator function for command completion. STATE lets us know whether * to start from scratch; without any state (i.e. STATE == 0), then we * start at the top of the list. */ static char *item_generator(const char *text, int state, const char *item, cpl_item_t type) { static int list_index, len; char *name; /* If this is a new word to complete, initialize now. This includes * saving the length of TEXT for efficiency, and initializing the index * variable to 0. */ if (!state) { list_index = 0; len = strlen(text); switch(type) { case ITEM_ARG: get_items(item); break; case ITEM_HELP: get_arguments(item); break; } } /* Return the next name which partially matches from the command list. */ while (items && list_index < items->list.size()) { name = (char *)items->list[list_index]; list_index++; if (bstrncmp(name, text, len)) { char *ret = (char *) actuallymalloc(strlen(name)+1); strcpy(ret, name); return ret; } } /* If no names matched, then return NULL. */ return ((char *)NULL); }
/* * Store a password at specified address in MD5 coding */ static void store_md5password(LEX *lc, RES_ITEM *item, int index, int pass) { s_password *pwd; URES *res_all = (URES *)my_config->m_res_all; lex_get_token(lc, T_STRING); if (pass == 1) { pwd = item->pwdvalue; if (pwd->value) { free(pwd->value); } /* * See if we are parsing an MD5 encoded password already. */ if (bstrncmp(lc->str, "[md5]", 5)) { pwd->encoding = p_encoding_md5; pwd->value = bstrdup(lc->str + 5); } else { unsigned int i, j; struct MD5Context md5c; unsigned char digest[CRYPTO_DIGEST_MD5_SIZE]; char sig[100]; MD5Init(&md5c); MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len); MD5Final(digest, &md5c); for (i = j = 0; i < sizeof(digest); i++) { sprintf(&sig[j], "%02x", digest[i]); j += 2; } pwd->encoding = p_encoding_md5; pwd->value = bstrdup(sig); } } scan_to_eol(lc); set_bit(index, res_all->hdr.item_present); }
/* * Check if a certain fileset include pattern shadows another pattern. */ static inline bool check_include_pattern_shadowing(JCR *jcr, const char *pattern1, const char *pattern2, bool recursive) { int len1, len2; bool retval = false; struct stat st1, st2; /* * See if one directory shadows the other or if two * files are hardlinked. */ if (lstat(pattern1, &st1) != 0) { berrno be; Jmsg(jcr, M_WARNING, 0, _("Cannot stat file %s: ERR=%s\n"), pattern1, be.bstrerror()); goto bail_out; } if (lstat(pattern2, &st2) != 0) { berrno be; Jmsg(jcr, M_WARNING, 0, _("Cannot stat file %s: ERR=%s\n"), pattern2, be.bstrerror()); goto bail_out; } if (S_ISDIR(st1.st_mode) && S_ISDIR(st2.st_mode)) { /* * Only check shadowing of directories when recursion is turned on. */ if (recursive ) { len1 = strlen(pattern1); len2 = strlen(pattern2); /* * See if one pattern shadows the other. */ if (((len1 < len2 && pattern1[len1] == '\0' && IsPathSeparator(pattern2[len1])) || (len1 > len2 && IsPathSeparator(pattern1[len2]) && pattern1[len1] == '\0')) && bstrncmp(pattern1, pattern2, MIN(len1, len2))) { /* * If both directories have the same st_dev they shadow * each other e.g. are not on seperate filesystems. */ if (st1.st_dev == st2.st_dev) { retval = true; } } } } else { /* * See if the two files are hardlinked. */ if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) { retval = true; } } bail_out: return retval; }
FileRecord *Dir_resolve_file(Dir *dir, bstring pattern, bstring path) { FileRecord *file = NULL; bstring target = NULL; bstring prefix = NULL; check(Dir_lazy_normalize_base(dir) == 0, "Failed to normalize base path when requesting %s", bdata(path)); file = FileRecord_cache_check(dir, path); if(file) { // TODO: double check this gives the right users count file->users++; return file; } int paren = bstrchr(pattern, '('); prefix = (paren > 0) ? bHead(pattern, paren) : bstrcpy(pattern); check(bchar(prefix, 0) == '/', "Route '%s' pointing to directory must have pattern with leading '/'", bdata(pattern)); check(blength(prefix) < MAX_DIR_PATH, "Prefix is too long, must be less than %d", MAX_DIR_PATH); debug("Building target from base: %s pattern: %s prefix: %s path: %s index_file: %s", bdata(dir->normalized_base), bdata(pattern), bdata(prefix), bdata(path), bdata(dir->index_file)); if(bchar(path, blength(path) - 1) == '/') { // a directory so figureo out the index file target = bformat("%s%s%s", bdata(dir->normalized_base), path->data + blength(prefix) - 1, bdata(dir->index_file)); } else if(biseq(prefix, path)) { target = bformat("%s%s", bdata(dir->normalized_base), bdata(path)); } else { target = bformat("%s%s", bdata(dir->normalized_base), path->data + blength(prefix) - 1); } check(target, "Couldn't construct target path for %s", bdata(path)); check_debug(normalize_path(target) == 0, "Failed to normalize target path: %s", bdata(target)); check_debug(bstrncmp(target, dir->normalized_base, blength(dir->normalized_base)) == 0, "Request for path %s does not start with %s base after normalizing.", bdata(target), bdata(dir->base)); // the FileRecord now owns the target file = Dir_find_file(target, dir->default_ctype); check_debug(file, "Error opening file: %s", bdata(target)); // Increment the user count because we're adding it to the cache file->users++; file->request_path = bstrcpy(path); Cache_add(dir->fr_cache, file); return file; error: bdestroy(target); FileRecord_release(file); return NULL; }
/* * Setup device, jcr, and prepare to access device. * If the caller wants read access, acquire the device, otherwise, * the caller will do it. */ static DCR *setup_to_access_device(JCR *jcr, char *dev_name, const char *VolumeName, int mode) { DEVICE *dev; char *p; DEVRES *device; DCR *dcr; char VolName[MAX_NAME_LENGTH]; init_reservations_lock(); /* * If no volume name already given and no bsr, and it is a file, * try getting name from Filename */ if (VolumeName) { bstrncpy(VolName, VolumeName, sizeof(VolName)); if (strlen(VolumeName) >= MAX_NAME_LENGTH) { Jmsg0(jcr, M_ERROR, 0, _("Volume name or names is too long. Please use a .bsr file.\n")); } } else { VolName[0] = 0; } if (!jcr->bsr && VolName[0] == 0) { if (!bstrncmp(dev_name, "/dev/", 5)) { /* Try stripping file part */ p = dev_name + strlen(dev_name); while (p >= dev_name && !IsPathSeparator(*p)) p--; if (IsPathSeparator(*p)) { bstrncpy(VolName, p+1, sizeof(VolName)); *p = 0; } } } if ((device=find_device_res(dev_name, mode)) == NULL) { Jmsg2(jcr, M_FATAL, 0, _("Cannot find device \"%s\" in config file %s.\n"), dev_name, configfile); return NULL; } dev = init_dev(jcr, device); if (!dev) { Jmsg1(jcr, M_FATAL, 0, _("Cannot init device %s\n"), dev_name); return NULL; } device->dev = dev; jcr->dcr = dcr = new_dcr(jcr, NULL, dev); if (VolName[0]) { bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName)); } bstrncpy(dcr->dev_name, device->device_name, sizeof(dcr->dev_name)); create_restore_volume_list(jcr); if (mode) { /* read only access? */ Dmsg0(100, "Acquire device for read\n"); if (!acquire_device_for_read(dcr)) { return NULL; } jcr->read_dcr = dcr; } else { if (!first_open_device(dcr)) { Jmsg1(jcr, M_FATAL, 0, _("Cannot open %s\n"), dev->print_name()); return NULL; } jcr->dcr = dcr; /* write dcr */ } return dcr; }
/* * 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; }
/* * Common routine for both label and relabel */ static int do_label(UAContext *ua, const char *cmd, bool relabel) { USTORERES store; BSOCK *sd; char dev_name[MAX_NAME_LENGTH]; MEDIA_DBR mr, omr; POOL_DBR pr; bool print_reminder = true; bool label_barcodes = false; bool label_encrypt = false; int ok = FALSE; int i, j; int drive; bool media_record_exists = false; static const char *barcode_keywords[] = { "barcode", "barcodes", NULL }; memset(&pr, 0, sizeof(pr)); if (!open_client_db(ua)) { return 1; } /* * Look for one of the barcode keywords */ if (!relabel && (i = find_arg_keyword(ua, barcode_keywords)) >= 0) { /* * Now find the keyword in the list */ if ((j = find_arg(ua, barcode_keywords[i])) > 0) { *ua->argk[j] = 0; /* zap barcode keyword */ } label_barcodes = true; } /* * Look for the encrypt keyword */ if ((i = find_arg(ua, "encrypt")) > 0) { *ua->argk[i] = 0; /* zap encrypt keyword */ label_encrypt = true; } store.store = get_storage_resource(ua, true, label_barcodes); if (!store.store) { return 1; } switch (store.store->Protocol) { case APT_NDMPV2: case APT_NDMPV3: case APT_NDMPV4: /* * See if the user selected a NDMP storage device but its * handled by a native Bareos storage daemon e.g. we have * a paired_storage pointer. */ if (store.store->paired_storage) { store.store = store.store->paired_storage; } else { ua->warning_msg(_("Storage has non-native protocol.\n")); return 1; } break; default: break; } pm_strcpy(store.store_source, _("command line")); set_wstorage(ua->jcr, &store); drive = get_storage_drive(ua, store.store); if (label_barcodes) { label_from_barcodes(ua, drive, label_encrypt); return 1; } /* * If relabel get name of Volume to relabel */ if (relabel) { /* * Check for oldvolume=name */ i = find_arg_with_value(ua, "oldvolume"); if (i >= 0) { bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName)); if (db_get_media_record(ua->jcr, ua->db, &omr)) { goto checkVol; } ua->error_msg("%s", db_strerror(ua->db)); } /* * No keyword or Vol not found, ask user to select */ if (!select_media_dbr(ua, &omr)) { return 1; } /* * Require Volume to be Purged or Recycled */ checkVol: if (!bstrcmp(omr.VolStatus, "Purged") && !bstrcmp(omr.VolStatus, "Recycle")) { ua->error_msg(_("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"), omr.VolumeName, omr.VolStatus); return 1; } } /* * Check for volume=NewVolume */ i = find_arg_with_value(ua, "volume"); if (i >= 0) { pm_strcpy(ua->cmd, ua->argv[i]); goto checkName; } /* * Get a new Volume name */ for ( ;; ) { media_record_exists = false; if (!get_cmd(ua, _("Enter new Volume name: "))) { return 1; } checkName: if (!is_volume_name_legal(ua, ua->cmd)) { continue; } /* * Search by Media name so set VolumeName and clear MediaId. */ mr.MediaId = 0; bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName)); /* * If VolBytes are zero the Volume is not labeled */ if (db_get_media_record(ua->jcr, ua->db, &mr)) { if (mr.VolBytes != 0) { ua->error_msg(_("Media record for new Volume \"%s\" already exists.\n"), mr.VolumeName); continue; } media_record_exists = true; } break; /* Got it */ } /* * If autochanger, request slot */ i = find_arg_with_value(ua, "slot"); if (i >= 0) { mr.Slot = atoi(ua->argv[i]); if (mr.Slot < 0) { mr.Slot = 0; } mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */ } else if (store.store->autochanger) { if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) { return 1; } mr.Slot = ua->pint32_val; if (mr.Slot < 0) { mr.Slot = 0; } mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */ } set_storageid_in_mr(store.store, &mr); bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType)); /* * Must select Pool if not already done */ if (pr.PoolId == 0) { memset(&pr, 0, sizeof(pr)); if (!select_pool_dbr(ua, &pr)) { return 1; } } /* * See if we need to generate a new passphrase for hardware encryption. */ if (label_encrypt) { ua->info_msg(_("Generating new hardware encryption key\n")); if (!generate_new_encryption_key(ua, &mr)) { return 1; } } ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive); if (ok) { sd = ua->jcr->store_bsock; if (relabel) { /* * Delete the old media record */ if (!db_delete_media_record(ua->jcr, ua->db, &omr)) { ua->error_msg(_("Delete of Volume \"%s\" failed. ERR=%s"), omr.VolumeName, db_strerror(ua->db)); } else { ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"), omr.VolumeName); /* * Update the number of Volumes in the pool */ pr.NumVols--; if (!db_update_pool_record(ua->jcr, ua->db, &pr)) { ua->error_msg("%s", db_strerror(ua->db)); } } } if (ua->automount) { bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name)); ua->info_msg(_("Requesting to mount %s ...\n"), dev_name); bash_spaces(dev_name); sd->fsend("mount %s drive=%d", dev_name, drive); unbash_spaces(dev_name); /* * We use bget_dirmsg here and not bnet_recv because as part of * the mount request the stored can request catalog information for * any plugin who listens to the bsdEventLabelVerified event. * As we don't want to loose any non protocol data e.g. errors * without a 3xxx prefix we set the allow_any_message of * bget_dirmsg to true and as such is behaves like a normal * bnet_recv for any non protocol messages. */ while (bget_dirmsg(sd, true) >= 0) { ua->send_msg("%s", sd->msg); /* * Here we can get * 3001 OK mount. Device=xxx or * 3001 Mounted Volume vvvv * 3002 Device "DVD-Writer" (/dev/hdc) is mounted. * 3906 is cannot mount non-tape * So for those, no need to print a reminder */ if (bstrncmp(sd->msg, "3001 ", 5) || bstrncmp(sd->msg, "3002 ", 5) || bstrncmp(sd->msg, "3906 ", 5)) { print_reminder = false; } } } } if (print_reminder) { ua->info_msg(_("Do not forget to mount the drive!!!\n")); } close_sd_bsock(ua); return 1; }
/* * 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 (!bstrncmp(dir->msg, OKhello, sizeof(OKhello)-1)) { 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; }
static int ssh_parse_args(obfsproxyssh_client_session_t *session, const char * args) { obfsproxyssh_t *state = session->client->state; struct tagbstring hkey_rsa_prefix = bsStatic("hostkey-rsa="); struct tagbstring hkey_dss_prefix = bsStatic("hostkey-dsa="); struct tagbstring user_prefix = bsStatic("user="******"privkey="); struct tagbstring orport_prefix = bsStatic("orport="); struct tagbstring arg_str; struct bstrList *arg_list; bstring tmp; int i; /* * Arguments are passed in as a single NULL terminated string, * separated by ";" (Eg: "rocks=20;height=5.6m"). * * Supported args: * * "hostkey-rsa=XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX" * * "hostkey-dsa=YY:YY:YY:YY:YY:YY:YY:YY:YY:YY:YY:YY:YY:YY:YY:YY" * * "user=USERNAME" * * "privkey=PRIVATEKEY" "PEM" format RSA key, with the header/footer/ * * newlines stripped. * * "orport=XXXXX" Port on the remote peer's loopback interface that * Tor is listening on (Temporary argument since once * there's an actual server implementation it should * handle that automatically). */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Waddress" btfromcstr(arg_str, args); arg_list = bsplit(&arg_str, ';'); for (i = 0; i < arg_list->qty; i++) { if (0 == bstrncmp(&hkey_rsa_prefix, arg_list->entry[i], blength(&hkey_rsa_prefix))) { session->hostkey_rsa = bmidstr(arg_list->entry[i], blength(&hkey_rsa_prefix), blength(arg_list->entry[i]) - blength(&hkey_rsa_prefix)); } else if (0 == bstrncmp(&hkey_dss_prefix, arg_list->entry[i], blength(&hkey_dss_prefix))) { session->hostkey_dss = bmidstr(arg_list->entry[i], blength(&hkey_dss_prefix), blength(arg_list->entry[i]) - blength(&hkey_dss_prefix)); } else if (0 == bstrncmp(&user_prefix, arg_list->entry[i], blength(&user_prefix))) { session->user = bmidstr(arg_list->entry[i], blength(&user_prefix), blength(arg_list->entry[i]) - blength(&user_prefix)); } else if (0 == bstrncmp(&privkey_prefix, arg_list->entry[i], blength(&privkey_prefix))) { tmp = bmidstr(arg_list->entry[i], blength(&privkey_prefix), blength(arg_list->entry[i]) - blength(&user_prefix)); session->privkey_pem = ssh_arg_to_privkey(tmp); bdestroy(tmp); } else if (0 == bstrncmp(&orport_prefix, arg_list->entry[i], blength(&orport_prefix))) { tmp = bmidstr(arg_list->entry[i], blength(&orport_prefix), blength(arg_list->entry[i]) - blength(&orport_prefix)); #pragma GCC diagnostic ignored "-Wnonnull" session->orport = atoi(bdata(tmp)); bdestroy(tmp); } } #pragma GCC diagnostic pop bstrListDestroy(arg_list); if (NULL == session->hostkey_rsa && NULL == session->hostkey_dss) return -1; if (NULL == session->user || NULL == session->privkey_pem || 0 == session->orport) return -1; /* Generate libssh compatible keys from the PEM */ session->privkey = read_rsa_private_key_from_memory( bdata(session->privkey_pem), blength(session->privkey_pem)); if (NULL == session->privkey) { log_f(state, "SOCKS: Error: %s Unable to decode private key", bdata(session->socks_addr)); return -1; } return 0; }
/* * We read an ANSI label and compare the Volume name. We require * a VOL1 record of 80 characters followed by a HDR1 record containing * BAREOS.DATA in the filename field. We then read up to 3 more * header records (they are not required) and an EOF, at which * point, all is good. * * Returns: * VOL_OK Volume name OK * VOL_NO_LABEL No ANSI label on Volume * VOL_IO_ERROR I/O error on read * VOL_NAME_ERROR Wrong name in VOL1 record * VOL_LABEL_ERROR Probably an ANSI label, but something wrong * */ int read_ansi_ibm_label(DCR *dcr) { DEVICE * volatile dev = dcr->dev; JCR *jcr = dcr->jcr; char label[80]; /* tape label */ int status, i; char *VolName = dcr->VolumeName; bool ok = false; /* * Read VOL1, HDR1, HDR2 labels, but ignore the data * If tape read the following EOF mark, on disk do * not read. */ Dmsg0(100, "Read ansi label.\n"); if (!dev->is_tape()) { return VOL_OK; } dev->label_type = B_BAREOS_LABEL; /* assume Bareos label */ /* Read a maximum of 5 records VOL1, HDR1, ... HDR4 */ for (i=0; i < 6; i++) { do { status = dev->read(label, sizeof(label)); } while (status == -1 && errno == EINTR); if (status < 0) { berrno be; dev->clrerror(-1); Dmsg1(100, "Read device got: ERR=%s\n", be.bstrerror()); Mmsg2(jcr->errmsg, _("Read error on device %s in ANSI label. ERR=%s\n"), dev->dev_name, be.bstrerror()); Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); dev->VolCatInfo.VolCatErrors++; return VOL_IO_ERROR; } if (status == 0) { if (dev->at_eof()) { dev->set_eot(); /* second eof, set eot bit */ Dmsg0(100, "EOM on ANSI label\n"); Mmsg0(jcr->errmsg, _("Insane! End of tape while reading ANSI label.\n")); return VOL_LABEL_ERROR; /* at EOM this shouldn't happen */ } else { dev->set_ateof(); /* set eof state */ } } switch (i) { case 0: /* Want VOL1 label */ if (status == 80) { if (bstrncmp("VOL1", label, 4)) { ok = true; dev->label_type = B_ANSI_LABEL; Dmsg0(100, "Got ANSI VOL1 label\n"); } else { /* Try EBCDIC */ ebcdic_to_ascii(label, label, sizeof(label)); if (bstrncmp("VOL1", label, 4)) { ok = true;; dev->label_type = B_IBM_LABEL; Dmsg0(100, "Found IBM label.\n"); Dmsg0(100, "Got IBM VOL1 label\n"); } } } if (!ok) { Dmsg0(100, "No VOL1 label\n"); Mmsg0(jcr->errmsg, _("No VOL1 label while reading ANSI/IBM label.\n")); return VOL_NO_LABEL; /* No ANSI label */ } /* Compare Volume Names allow special wild card */ if (VolName && *VolName && *VolName != '*') { if (!same_label_names(VolName, &label[4])) { char *p = &label[4]; char *q; free_volume(dev); /* Store new Volume name */ q = dev->VolHdr.VolumeName; for (int i=0; *p != ' ' && i < 6; i++) { *q++ = *p++; } *q = 0; Dmsg0(100, "Call reserve_volume\n"); /* ***FIXME*** why is this reserve_volume() needed???? KES */ reserve_volume(dcr, dev->VolHdr.VolumeName); dev = dcr->dev; /* may have changed in reserve_volume */ Dmsg2(100, "Wanted ANSI Vol %s got %6s\n", VolName, dev->VolHdr.VolumeName); Mmsg2(jcr->errmsg, _("Wanted ANSI Volume \"%s\" got \"%s\"\n"), VolName, dev->VolHdr.VolumeName); return VOL_NAME_ERROR; } } break; case 1: if (dev->label_type == B_IBM_LABEL) { ebcdic_to_ascii(label, label, sizeof(label)); } if (status != 80 || !bstrncmp("HDR1", label, 4)) { Dmsg0(100, "No HDR1 label\n"); Mmsg0(jcr->errmsg, _("No HDR1 label while reading ANSI label.\n")); return VOL_LABEL_ERROR; } if (!bstrncmp("BAREOS.DATA", &label[4], 11)) { Dmsg1(100, "HD1 not Bareos label. Wanted BAREOS.DATA got %11s\n", &label[4]); Mmsg1(jcr->errmsg, _("ANSI/IBM Volume \"%s\" does not belong to Bareos.\n"), dev->VolHdr.VolumeName); return VOL_NAME_ERROR; /* Not a Bareos label */ } Dmsg0(100, "Got HDR1 label\n"); break; case 2: if (dev->label_type == B_IBM_LABEL) { ebcdic_to_ascii(label, label, sizeof(label)); } if (status != 80 || !bstrncmp("HDR2", label, 4)) { Dmsg0(100, "No HDR2 label\n"); Mmsg0(jcr->errmsg, _("No HDR2 label while reading ANSI/IBM label.\n")); return VOL_LABEL_ERROR; } Dmsg0(100, "Got ANSI HDR2 label\n"); break; default: if (status == 0) { Dmsg0(100, "ANSI label OK\n"); return VOL_OK; } if (dev->label_type == B_IBM_LABEL) { ebcdic_to_ascii(label, label, sizeof(label)); } if (status != 80 || !bstrncmp("HDR", label, 3)) { Dmsg0(100, "Unknown or bad ANSI/IBM label record.\n"); Mmsg0(jcr->errmsg, _("Unknown or bad ANSI/IBM label record.\n")); return VOL_LABEL_ERROR; } Dmsg0(100, "Got HDR label\n"); break; } } Dmsg0(100, "Too many records in ANSI/IBM label.\n"); Mmsg0(jcr->errmsg, _("Too many records in while reading ANSI/IBM label.\n")); return VOL_LABEL_ERROR; }