/** * @brief Convert a public key to a base64 encoded key. * * @param[in] key The key to hash * * @param[out] b64_key A pointer to store the allocated base64 encoded key. You * need to free the buffer. * * @return SSH_OK on success, SSH_ERROR on error. * * @see ssh_string_free_char() */ int ssh_pki_export_pubkey_base64(const ssh_key key, char **b64_key) { ssh_string key_blob; unsigned char *b64; if (key == NULL || b64_key == NULL) { return SSH_ERROR; } key_blob = pki_publickey_to_blob(key); if (key_blob == NULL) { return SSH_ERROR; } b64 = bin_to_base64(ssh_string_data(key_blob), ssh_string_len(key_blob)); ssh_string_free(key_blob); if (b64 == NULL) { return SSH_ERROR; } *b64_key = (char *)b64; return SSH_OK; }
void test_bin_to_base64() { int x = 0, compatible = 1, len; char res[100]; while(strcmp(test_bin_to_base64_data[x].test_str, "") != 0) { len = bin_to_base64(res, 100, test_bin_to_base64_data[x].test_str, strlen(test_bin_to_base64_data[x].test_str), compatible); CU_ASSERT(strcmp(res, test_bin_to_base64_data[x].base64_result) == 0); x++; } }
/* Respond to challenge from other end */ bool cram_md5_respond(BSOCK *bs, const char *password, int *tls_remote_need, bool *compatible) { char chal[MAXSTRING]; uint8_t hmac[20]; *compatible = false; if (bs->recv() <= 0) { bmicrosleep(5, 0); return false; } if (bs->msglen >= MAXSTRING) { Dmsg1(dbglvl, "Msg too long wanted auth cram... Got: %s", bs->msg); bmicrosleep(5, 0); return false; } Dmsg1(100, "cram-get received: %s", bs->msg); if (sscanf(bs->msg, "auth cram-md5c %s ssl=%d", chal, tls_remote_need) == 2) { *compatible = true; } else if (sscanf(bs->msg, "auth cram-md5 %s ssl=%d", chal, tls_remote_need) != 2) { if (sscanf(bs->msg, "auth cram-md5 %s\n", chal) != 1) { Dmsg1(dbglvl, "Cannot scan challenge: %s", bs->msg); bs->fsend(_("1999 Authorization failed.\n")); bmicrosleep(5, 0); return false; } } hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac); bs->msglen = bin_to_base64(bs->msg, 50, (char *)hmac, 16, *compatible) + 1; // Dmsg3(100, "get_auth: chal=%s pw=%s hmac=%s\n", chal, password, bs->msg); if (!bs->send()) { Dmsg1(dbglvl, "Send challenge failed. ERR=%s\n", bs->bstrerror()); return false; } Dmsg1(99, "sending resp to challenge: %s\n", bs->msg); if (bs->wait_data(180) <= 0 || bs->recv() <= 0) { Dmsg1(dbglvl, "Receive chanllenge response failed. ERR=%s\n", bs->bstrerror()); bmicrosleep(5, 0); return false; } if (bstrcmp(bs->msg, "1000 OK auth\n")) { return true; } Dmsg1(dbglvl, "Received bad response: %s\n", bs->msg); bmicrosleep(5, 0); return false; }
/* * Calculate the chksum of a whole file and updates: * - digest * - digest_stream * - digest_buffer * - digest_name * * Returns: true if digest calculation succeeded. * false if digest calculation failed. */ static bool calculate_file_chksum(JCR *jcr, FF_PKT *ff_pkt, DIGEST **digest, int *digest_stream, char **digest_buf, const char **digest_name) { /* * Create our digest context. * If this fails, the digest will be set to NULL and not used. */ if (ff_pkt->flags & FO_MD5) { *digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5); *digest_stream = STREAM_MD5_DIGEST; } else if (ff_pkt->flags & FO_SHA1) { *digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1); *digest_stream = STREAM_SHA1_DIGEST; } else if (ff_pkt->flags & FO_SHA256) { *digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256); *digest_stream = STREAM_SHA256_DIGEST; } else if (ff_pkt->flags & FO_SHA512) { *digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512); *digest_stream = STREAM_SHA512_DIGEST; } /* * compute MD5 or SHA1 hash */ if (*digest) { uint32_t size; char md[CRYPTO_DIGEST_MAX_SIZE]; size = sizeof(md); if (digest_file(jcr, ff_pkt, *digest) != 0) { jcr->JobErrors++; return false; } if (crypto_digest_finalize(*digest, (uint8_t *)md, &size)) { *digest_buf = (char *)malloc(BASE64_SIZE(size)); *digest_name = crypto_digest_name(*digest); bin_to_base64(*digest_buf, BASE64_SIZE(size), md, size, true); } } return true; }
/* * Generate a new encryption key for use in volume encryption. * We don't ask the user for a encryption key but generate a semi * random passphrase of the wanted length which is way stronger. * When the config has a wrap key we use that to wrap the newly * created passphrase using RFC3394 aes wrap and always convert * the passphrase into a base64 encoded string. This key is * stored in the database and is passed to the storage daemon * when needed. The storage daemon has the same wrap key per * director so it can unwrap the passphrase for use. * * Changing the wrap key will render any previously created * crypto keys useless so only change the wrap key after initial * setting when you know what you are doing and always store * the old key somewhere save so you can use bscrypto to * convert them for the new wrap key. */ static bool generate_new_encryption_key(UAContext *ua, MEDIA_DBR *mr) { int length; char *passphrase; passphrase = generate_crypto_passphrase(DEFAULT_PASSPHRASE_LENGTH); if (!passphrase) { ua->error_msg(_("Failed to generate new encryption passphrase for Volume %s.\n"), mr->VolumeName); return false; } /* * See if we need to wrap the passphrase. */ if (me->keyencrkey) { char *wrapped_passphrase; length = DEFAULT_PASSPHRASE_LENGTH + 8; wrapped_passphrase = (char *)malloc(length); memset(wrapped_passphrase, 0, length); aes_wrap((unsigned char *)me->keyencrkey, DEFAULT_PASSPHRASE_LENGTH / 8, (unsigned char *)passphrase, (unsigned char *)wrapped_passphrase); free(passphrase); passphrase = wrapped_passphrase; } else { length = DEFAULT_PASSPHRASE_LENGTH; } /* * The passphrase is always base64 encoded. */ bin_to_base64(mr->EncrKey, sizeof(mr->EncrKey), passphrase, length, true); free(passphrase); return true; }
bool get_or_create_fileset_record(JCR *jcr) { FILESET_DBR fsr; /* * Get or Create FileSet record */ memset(&fsr, 0, sizeof(FILESET_DBR)); bstrncpy(fsr.FileSet, jcr->res.fileset->hdr.name, sizeof(fsr.FileSet)); if (jcr->res.fileset->have_MD5) { struct MD5Context md5c; unsigned char digest[MD5HashSize]; memcpy(&md5c, &jcr->res.fileset->md5c, sizeof(md5c)); MD5Final(digest, &md5c); /* * Keep the flag (last arg) set to false otherwise old FileSets will * get new MD5 sums and the user will get Full backups on everything */ bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false); bstrncpy(jcr->res.fileset->MD5, fsr.MD5, sizeof(jcr->res.fileset->MD5)); } else { Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n")); } if (!jcr->res.fileset->ignore_fs_changes || !db_get_fileset_record(jcr, jcr->db, &fsr)) { if (!db_create_fileset_record(jcr, jcr->db, &fsr)) { Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"), fsr.FileSet, db_strerror(jcr->db)); return false; } } jcr->jr.FileSetId = fsr.FileSetId; bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime)); Dmsg2(119, "Created FileSet %s record %u\n", jcr->res.fileset->hdr.name, jcr->jr.FileSetId); return true; }
/* * Note, we receive the whole attribute record, but we select out only the stat * packet, VolSessionId, VolSessionTime, FileIndex, file type, and file name to * store in the catalog. */ static void update_attribute(JCR *jcr, char *msg, int32_t msglen) { unser_declare; uint32_t VolSessionId, VolSessionTime; int32_t Stream; uint32_t FileIndex; char *p; int len; char *fname, *attr; ATTR_DBR *ar = NULL; uint32_t reclen; /* * Start transaction allocates jcr->attr and jcr->ar if needed */ db_start_transaction(jcr, jcr->db); /* start transaction if not already open */ ar = jcr->ar; /* * Start by scanning directly in the message buffer to get Stream * there may be a cached attr so we cannot yet write into * jcr->attr or jcr->ar */ p = msg; skip_nonspaces(&p); /* UpdCat */ skip_spaces(&p); skip_nonspaces(&p); /* Job=nnn */ skip_spaces(&p); skip_nonspaces(&p); /* "FileAttributes" */ p += 1; /* * The following "SD header" fields are serialized */ unser_begin(p, 0); unser_uint32(VolSessionId); /* VolSessionId */ unser_uint32(VolSessionTime); /* VolSessionTime */ unser_int32(FileIndex); /* FileIndex */ unser_int32(Stream); /* Stream */ unser_uint32(reclen); /* Record length */ p += unser_length(p); /* Raw record follows */ /** * At this point p points to the raw record, which varies according * to what kind of a record (Stream) was sent. Note, the integer * fields at the beginning of these "raw" records are in ASCII with * spaces between them so one can use scanf or manual scanning to * extract the fields. * * File Attributes * File_index * File type * Filename (full path) * Encoded attributes * Link name (if type==FT_LNK or FT_LNKSAVED) * Encoded extended-attributes (for Win32) * Delta sequence number (32 bit int) * * Restore Object * File_index * File_type * Object_index * Object_len (possibly compressed) * Object_full_len (not compressed) * Object_compression * Plugin_name * Object_name * Binary Object data */ Dmsg1(400, "UpdCat msg=%s\n", msg); Dmsg5(400, "UpdCat VolSessId=%d VolSessT=%d FI=%d Strm=%d reclen=%d\n", VolSessionId, VolSessionTime, FileIndex, Stream, reclen); jcr->SDJobBytes += reclen; /* update number of bytes transferred for quotas */ /* * Depending on the stream we are handling dispatch. */ switch (Stream) { case STREAM_UNIX_ATTRIBUTES: case STREAM_UNIX_ATTRIBUTES_EX: if (jcr->cached_attribute) { Dmsg2(400, "Cached attr. Stream=%d fname=%s\n", ar->Stream, ar->fname); if (!db_create_attributes_record(jcr, jcr->db, ar)) { Jmsg1(jcr, M_FATAL, 0, _("Attribute create error: ERR=%s"), db_strerror(jcr->db)); } jcr->cached_attribute = false; } /* * Any cached attr is flushed so we can reuse jcr->attr and jcr->ar */ jcr->attr = check_pool_memory_size(jcr->attr, msglen); memcpy(jcr->attr, msg, msglen); p = jcr->attr - msg + p; /* point p into jcr->attr */ skip_nonspaces(&p); /* skip FileIndex */ skip_spaces(&p); ar->FileType = str_to_int32(p); skip_nonspaces(&p); /* skip FileType */ skip_spaces(&p); fname = p; len = strlen(fname); /* length before attributes */ attr = &fname[len+1]; ar->DeltaSeq = 0; if (ar->FileType == FT_REG) { p = attr + strlen(attr) + 1; /* point to link */ p = p + strlen(p) + 1; /* point to extended attributes */ p = p + strlen(p) + 1; /* point to delta sequence */ /* * Older FDs don't have a delta sequence, so check if it is there */ if (p - jcr->attr < msglen) { ar->DeltaSeq = str_to_int32(p); /* delta_seq */ } } Dmsg2(400, "dird<stored: stream=%d %s\n", Stream, fname); Dmsg1(400, "dird<stored: attr=%s\n", attr); ar->attr = attr; ar->fname = fname; if (ar->FileType == FT_DELETED) { ar->FileIndex = 0; /* special value */ } else { ar->FileIndex = FileIndex; } ar->Stream = Stream; ar->link = NULL; if (jcr->mig_jcr) { ar->JobId = jcr->mig_jcr->JobId; } else { ar->JobId = jcr->JobId; } ar->Digest = NULL; ar->DigestType = CRYPTO_DIGEST_NONE; jcr->cached_attribute = true; Dmsg2(400, "dird<filed: stream=%d %s\n", Stream, fname); Dmsg1(400, "dird<filed: attr=%s\n", attr); break; case STREAM_RESTORE_OBJECT: { ROBJECT_DBR ro; memset(&ro, 0, sizeof(ro)); ro.Stream = Stream; ro.FileIndex = FileIndex; if (jcr->mig_jcr) { ro.JobId = jcr->mig_jcr->JobId; } else { ro.JobId = jcr->JobId; } Dmsg1(100, "Robj=%s\n", p); skip_nonspaces(&p); /* skip FileIndex */ skip_spaces(&p); ro.FileType = str_to_int32(p); /* FileType */ skip_nonspaces(&p); skip_spaces(&p); ro.object_index = str_to_int32(p); /* Object Index */ skip_nonspaces(&p); skip_spaces(&p); ro.object_len = str_to_int32(p); /* object length possibly compressed */ skip_nonspaces(&p); skip_spaces(&p); ro.object_full_len = str_to_int32(p); /* uncompressed object length */ skip_nonspaces(&p); skip_spaces(&p); ro.object_compression = str_to_int32(p); /* compression */ skip_nonspaces(&p); skip_spaces(&p); ro.plugin_name = p; /* point to plugin name */ len = strlen(ro.plugin_name); ro.object_name = &ro.plugin_name[len+1]; /* point to object name */ len = strlen(ro.object_name); ro.object = &ro.object_name[len+1]; /* point to object */ ro.object[ro.object_len] = 0; /* add zero for those who attempt printing */ Dmsg7(100, "oname=%s stream=%d FT=%d FI=%d JobId=%d, obj_len=%d\nobj=\"%s\"\n", ro.object_name, ro.Stream, ro.FileType, ro.FileIndex, ro.JobId, ro.object_len, ro.object); /* * Store it. */ if (!db_create_restore_object_record(jcr, jcr->db, &ro)) { Jmsg1(jcr, M_FATAL, 0, _("Restore object create error. %s"), db_strerror(jcr->db)); } break; } default: if (crypto_digest_stream_type(Stream) != CRYPTO_DIGEST_NONE) { fname = p; if (ar->FileIndex != FileIndex) { Jmsg3(jcr, M_WARNING, 0, _("%s not same File=%d as attributes=%d\n"), stream_to_ascii(Stream), FileIndex, ar->FileIndex); } else { /* * Update digest in catalog */ char digestbuf[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)]; int len = 0; int type = CRYPTO_DIGEST_NONE; switch(Stream) { case STREAM_MD5_DIGEST: len = CRYPTO_DIGEST_MD5_SIZE; type = CRYPTO_DIGEST_MD5; break; case STREAM_SHA1_DIGEST: len = CRYPTO_DIGEST_SHA1_SIZE; type = CRYPTO_DIGEST_SHA1; break; case STREAM_SHA256_DIGEST: len = CRYPTO_DIGEST_SHA256_SIZE; type = CRYPTO_DIGEST_SHA256; break; case STREAM_SHA512_DIGEST: len = CRYPTO_DIGEST_SHA512_SIZE; type = CRYPTO_DIGEST_SHA512; break; default: /* * Never reached ... */ Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. Unsupported digest stream type: %d"), Stream); } bin_to_base64(digestbuf, sizeof(digestbuf), fname, len, true); Dmsg3(400, "DigestLen=%d Digest=%s type=%d\n", strlen(digestbuf), digestbuf, Stream); if (jcr->cached_attribute) { ar->Digest = digestbuf; ar->DigestType = type; Dmsg2(400, "Cached attr with digest. Stream=%d fname=%s\n", ar->Stream, ar->fname); /* * Update BaseFile table */ if (!db_create_attributes_record(jcr, jcr->db, ar)) { Jmsg1(jcr, M_FATAL, 0, _("attribute create error. %s"), db_strerror(jcr->db)); } jcr->cached_attribute = false; } else { if (!db_add_digest_to_file_record(jcr, jcr->db, ar->FileId, digestbuf, type)) { Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. %s"), db_strerror(jcr->db)); } } } } break; } }
/* * Verify attributes of the requested files on the Volume * */ void do_verify_volume(JCR *jcr) { BSOCK *sd, *dir; POOLMEM *fname; /* original file name */ POOLMEM *lname; /* link name */ int32_t stream; uint32_t size; uint32_t VolSessionId, VolSessionTime, file_index; uint32_t record_file_index; char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)]; int type, stat; sd = jcr->store_bsock; if (!sd) { Jmsg(jcr, M_FATAL, 0, _("Storage command not issued before Verify.\n")); jcr->setJobStatus(JS_FatalError); return; } dir = jcr->dir_bsock; jcr->setJobStatus(JS_Running); LockRes(); CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL); UnlockRes(); uint32_t buf_size; if (client) { buf_size = client->max_network_buffer_size; } else { buf_size = 0; /* use default */ } if (!sd->set_buffer_size(buf_size, BNET_SETBUF_WRITE)) { jcr->setJobStatus(JS_FatalError); return; } jcr->buf_size = sd->msglen; fname = get_pool_memory(PM_FNAME); lname = get_pool_memory(PM_FNAME); /* * Get a record from the Storage daemon */ while (bget_msg(sd) >= 0 && !job_canceled(jcr)) { /* * First we expect a Stream Record Header */ if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index, &stream, &size) != 5) { Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg); goto bail_out; } Dmsg3(30, "Got hdr: FilInx=%d Stream=%d size=%d.\n", file_index, stream, size); /* * Now we expect the Stream Data */ if (bget_msg(sd) < 0) { Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), sd->bstrerror()); goto bail_out; } if (size != ((uint32_t)sd->msglen)) { Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size); goto bail_out; } Dmsg2(30, "Got stream data %s, len=%d\n", stream_to_ascii(stream), sd->msglen); /* File Attributes stream */ switch (stream) { case STREAM_UNIX_ATTRIBUTES: case STREAM_UNIX_ATTRIBUTES_EX: char *ap, *lp, *fp; Dmsg0(400, "Stream=Unix Attributes.\n"); if ((int)sizeof_pool_memory(fname) < sd->msglen) { fname = realloc_pool_memory(fname, sd->msglen + 1); } if ((int)sizeof_pool_memory(lname) < sd->msglen) { lname = realloc_pool_memory(lname, sd->msglen + 1); } *fname = 0; *lname = 0; /* * An Attributes record consists of: * File_index * Type (FT_types) * Filename * Attributes * Link name (if file linked i.e. FT_LNK) * Extended Attributes (if Win32) */ if (sscanf(sd->msg, "%d %d", &record_file_index, &type) != 2) { Jmsg(jcr, M_FATAL, 0, _("Error scanning record header: %s\n"), sd->msg); Dmsg0(0, "\nError scanning header\n"); goto bail_out; } Dmsg2(30, "Got Attr: FilInx=%d type=%d\n", record_file_index, type); ap = sd->msg; while (*ap++ != ' ') /* skip record file index */ ; while (*ap++ != ' ') /* skip type */ ; /* Save filename and position to attributes */ fp = fname; while (*ap != 0) { *fp++ = *ap++; /* copy filename to fname */ } *fp = *ap++; /* terminate filename & point to attribs */ Dmsg2(100, "File=%s Attr=%s\n", fname, ap); /* Skip to Link name */ if (type == FT_LNK || type == FT_LNKSAVED) { lp = ap; while (*lp++ != 0) { ; } pm_strcat(lname, lp); /* "save" link name */ } else { *lname = 0; } jcr->lock(); jcr->JobFiles++; jcr->num_files_examined++; pm_strcpy(jcr->last_fname, fname); /* last file examined */ jcr->unlock(); /* * Send file attributes to Director * File_index * Stream * Verify Options * Filename (full path) * Encoded attributes * Link name (if type==FT_LNK) * For a directory, link is the same as fname, but with trailing * slash. For a linked file, link is the link. */ /* Send file attributes to Director */ Dmsg2(200, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, fname); if (type == FT_LNK || type == FT_LNKSAVED) { stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES, "pinsug5", fname, 0, ap, 0, lname, 0); /* for a deleted record, we set fileindex=0 */ } else if (type == FT_DELETED) { stat = dir->fsend("%d %d %s %s%c%s%c%c", 0, STREAM_UNIX_ATTRIBUTES, "pinsug5", fname, 0, ap, 0, 0); } else { stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES, "pinsug5", fname, 0, ap, 0, 0); } Dmsg2(200, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg); if (!stat) { Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), dir->bstrerror()); goto bail_out; } break; case STREAM_MD5_DIGEST: bin_to_base64(digest, sizeof(digest), (char *)sd->msg, CRYPTO_DIGEST_MD5_SIZE, true); Dmsg2(400, "send inx=%d MD5=%s\n", jcr->JobFiles, digest); dir->fsend("%d %d %s *MD5-%d*", jcr->JobFiles, STREAM_MD5_DIGEST, digest, jcr->JobFiles); Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg); break; case STREAM_SHA1_DIGEST: bin_to_base64(digest, sizeof(digest), (char *)sd->msg, CRYPTO_DIGEST_SHA1_SIZE, true); Dmsg2(400, "send inx=%d SHA1=%s\n", jcr->JobFiles, digest); dir->fsend("%d %d %s *SHA1-%d*", jcr->JobFiles, STREAM_SHA1_DIGEST, digest, jcr->JobFiles); Dmsg2(20, "bfiled>bdird: SHA1 len=%d: msg=%s\n", dir->msglen, dir->msg); break; case STREAM_SHA256_DIGEST: bin_to_base64(digest, sizeof(digest), (char *)sd->msg, CRYPTO_DIGEST_SHA256_SIZE, true); Dmsg2(400, "send inx=%d SHA256=%s\n", jcr->JobFiles, digest); dir->fsend("%d %d %s *SHA256-%d*", jcr->JobFiles, STREAM_SHA256_DIGEST, digest, jcr->JobFiles); Dmsg2(20, "bfiled>bdird: SHA256 len=%d: msg=%s\n", dir->msglen, dir->msg); break; case STREAM_SHA512_DIGEST: bin_to_base64(digest, sizeof(digest), (char *)sd->msg, CRYPTO_DIGEST_SHA512_SIZE, true); Dmsg2(400, "send inx=%d SHA512=%s\n", jcr->JobFiles, digest); dir->fsend("%d %d %s *SHA512-%d*", jcr->JobFiles, STREAM_SHA512_DIGEST, digest, jcr->JobFiles); Dmsg2(20, "bfiled>bdird: SHA512 len=%d: msg=%s\n", dir->msglen, dir->msg); break; /* * Restore stream object is counted, but not restored here */ case STREAM_RESTORE_OBJECT: jcr->lock(); jcr->JobFiles++; jcr->num_files_examined++; jcr->unlock(); break; /* Ignore everything else */ default: break; } /* end switch */ } /* end while bnet_get */ jcr->setJobStatus(JS_Terminated); goto ok_out; bail_out: jcr->setJobStatus(JS_ErrorTerminated); ok_out: if (jcr->compress_buf) { free(jcr->compress_buf); jcr->compress_buf = NULL; } free_pool_memory(fname); free_pool_memory(lname); Dmsg2(050, "End Verify-Vol. Files=%d Bytes=%" lld "\n", jcr->JobFiles, jcr->JobBytes); }
/** * @brief Write the current server as known in the known hosts file. * * This will create the known hosts file if it does not exist. You generaly use * it when ssh_is_server_known() answered SSH_SERVER_NOT_KNOWN. * * @param[in] session The ssh session to use. * * @return SSH_OK on success, SSH_ERROR on error. */ int ssh_write_knownhost(ssh_session session) { ssh_string pubkey; unsigned char *pubkey_64; char buffer[4096] = {0}; FILE *file; char *dir; char *host; char *hostport; size_t len = 0; if (session->host == NULL) { ssh_set_error(session, SSH_FATAL, "Can't write host in known hosts if the hostname isn't known"); return SSH_ERROR; } host = ssh_lowercase(session->host); /* If using a nonstandard port, save the host in the [host]:port format */ if(session->port != 22){ hostport = ssh_hostport(host,session->port); SAFE_FREE(host); host=hostport; hostport=NULL; } if (session->knownhosts == NULL) { if (ssh_options_apply(session) < 0) { ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file"); return SSH_ERROR; } } if(session->current_crypto==NULL) { ssh_set_error(session, SSH_FATAL, "No current crypto context"); return SSH_ERROR; } pubkey = session->current_crypto->server_pubkey; if(pubkey == NULL){ ssh_set_error(session, SSH_FATAL, "No public key present"); return SSH_ERROR; } /* Check if ~/.ssh exists and create it if not */ dir = ssh_dirname(session->knownhosts); if (dir == NULL) { ssh_set_error(session, SSH_FATAL, "%s", strerror(errno)); return -1; } if (! ssh_file_readaccess_ok(dir)) { if (ssh_mkdir(dir, 0700) < 0) { ssh_set_error(session, SSH_FATAL, "Cannot create %s directory.", dir); SAFE_FREE(dir); return -1; } } SAFE_FREE(dir); file = fopen(session->knownhosts, "a"); if (file == NULL) { ssh_set_error(session, SSH_FATAL, "Couldn't open known_hosts file %s for appending: %s", session->knownhosts, strerror(errno)); SAFE_FREE(host); return -1; } if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) { /* openssh uses a different format for ssh-rsa1 keys. Be compatible --kv */ ssh_public_key key; char *e_string = NULL; char *n_string = NULL; bignum e = NULL; bignum n = NULL; int rsa_size; #ifdef HAVE_LIBGCRYPT gcry_sexp_t sexp; #endif key = publickey_from_string(session, pubkey); if (key == NULL) { fclose(file); SAFE_FREE(host); return -1; } #ifdef HAVE_LIBGCRYPT sexp = gcry_sexp_find_token(key->rsa_pub, "e", 0); if (sexp == NULL) { publickey_free(key); fclose(file); SAFE_FREE(host); return -1; } e = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG); gcry_sexp_release(sexp); if (e == NULL) { publickey_free(key); fclose(file); SAFE_FREE(host); return -1; } sexp = gcry_sexp_find_token(key->rsa_pub, "n", 0); if (sexp == NULL) { publickey_free(key); bignum_free(e); fclose(file); SAFE_FREE(host); return -1; } n = gcry_sexp_nth_mpi(sexp, 1, GCRYMPI_FMT_USG); gcry_sexp_release(sexp); if (n == NULL) { publickey_free(key); bignum_free(e); fclose(file); SAFE_FREE(host); return -1; } rsa_size = (gcry_pk_get_nbits(key->rsa_pub) + 7) / 8; #elif defined HAVE_LIBCRYPTO e = key->rsa_pub->e; n = key->rsa_pub->n; rsa_size = RSA_size(key->rsa_pub); #endif e_string = bignum_bn2dec(e); n_string = bignum_bn2dec(n); if (e_string == NULL || n_string == NULL) { #ifdef HAVE_LIBGCRYPT bignum_free(e); bignum_free(n); SAFE_FREE(e_string); SAFE_FREE(n_string); #elif defined HAVE_LIBCRYPTO OPENSSL_free(e_string); OPENSSL_free(n_string); #endif publickey_free(key); fclose(file); SAFE_FREE(host); return -1; } snprintf(buffer, sizeof(buffer), "%s %d %s %s\n", host, rsa_size << 3, e_string, n_string); #ifdef HAVE_LIBGCRYPT bignum_free(e); bignum_free(n); SAFE_FREE(e_string); SAFE_FREE(n_string); #elif defined HAVE_LIBCRYPTO OPENSSL_free(e_string); OPENSSL_free(n_string); #endif publickey_free(key); } else { pubkey_64 = bin_to_base64(pubkey->string, ssh_string_len(pubkey)); if (pubkey_64 == NULL) { fclose(file); SAFE_FREE(host); return -1; } snprintf(buffer, sizeof(buffer), "%s %s %s\n", host, session->current_crypto->server_pubkey_type, pubkey_64); SAFE_FREE(pubkey_64); } SAFE_FREE(host); len = strlen(buffer); if (fwrite(buffer, len, 1, file) != 1 || ferror(file)) { fclose(file); return -1; } fclose(file); return 0; }
/* Authorize other end * Codes that tls_local_need and tls_remote_need can take: * * BNET_TLS_NONE I cannot do tls * BNET_TLS_OK I can do tls, but it is not required on my end * BNET_TLS_REQUIRED tls is required on my end * * Returns: false if authentication failed * true if OK */ bool cram_md5_challenge(BSOCK *bs, const char *password, int tls_local_need, bool compatible) { struct timeval t1; struct timeval t2; struct timezone tz; int i; bool ok; char chal[MAXSTRING]; char host[MAXSTRING]; uint8_t hmac[20]; gettimeofday(&t1, &tz); for (i=0; i<4; i++) { gettimeofday(&t2, &tz); } srandom((t1.tv_sec&0xffff) * (t2.tv_usec&0xff)); if (!gethostname(host, sizeof(host))) { bstrncpy(host, my_name, sizeof(host)); } /* Send challenge -- no hashing yet */ bsnprintf(chal, sizeof(chal), "<%u.%u@%s>", (uint32_t)random(), (uint32_t)time(NULL), host); if (compatible) { Dmsg2(dbglvl, "send: auth cram-md5 %s ssl=%d\n", chal, tls_local_need); if (!bs->fsend("auth cram-md5 %s ssl=%d\n", chal, tls_local_need)) { Dmsg1(dbglvl, "Bnet send challenge comm error. ERR=%s\n", bs->bstrerror()); return false; } } else { /* Old non-compatible system */ Dmsg2(dbglvl, "send: auth cram-md5 %s ssl=%d\n", chal, tls_local_need); if (!bs->fsend("auth cram-md5 %s ssl=%d\n", chal, tls_local_need)) { Dmsg1(dbglvl, "Bnet send challenge comm error. ERR=%s\n", bs->bstrerror()); return false; } } /* Read hashed response to challenge */ if (bs->wait_data(180) <= 0 || bs->recv() <= 0) { Dmsg1(dbglvl, "Bnet receive challenge response comm error. ERR=%s\n", bs->bstrerror()); bmicrosleep(5, 0); return false; } /* Attempt to duplicate hash with our password */ hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac); bin_to_base64(host, sizeof(host), (char *)hmac, 16, compatible); ok = bstrcmp(bs->msg, host); if (ok) { Dmsg1(dbglvl, "Authenticate OK %s\n", host); } else { bin_to_base64(host, sizeof(host), (char *)hmac, 16, false); ok = bstrcmp(bs->msg, host); if (!ok) { Dmsg2(dbglvl, "Authenticate NOT OK: wanted %s, got %s\n", host, bs->msg); } } if (ok) { bs->fsend("1000 OK auth\n"); } else { bs->fsend(_("1999 Authorization failed.\n")); bmicrosleep(5, 0); } return ok; }
int main(int argc, char *const *argv) { int retval = 0; int ch, kfd, length; bool base64_transform = false, clear_encryption = false, drive_encryption_status = false, generate_passphrase = false, populate_cache = false, set_encryption = false, show_keydata = false, volume_encryption_status = false, wrapped_keys = false; char *keyfile = NULL; char *cache_file = NULL; char *wrap_keyfile = NULL; char keydata[64]; char wrapdata[64]; setlocale(LC_ALL, ""); bindtextdomain("bareos", LOCALEDIR); textdomain("bareos"); while ((ch = getopt(argc, argv, "bcd:eg:k:p:s:vw:?")) != -1) { switch (ch) { case 'b': base64_transform = true; break; case 'c': clear_encryption = true; break; case 'd': debug_level = atoi(optarg); if (debug_level <= 0) { debug_level = 1; } break; case 'e': drive_encryption_status = true; break; case 'g': generate_passphrase = true; if (keyfile) { usage(); goto bail_out; } keyfile = bstrdup(optarg); break; case 'k': show_keydata = true; if (keyfile) { usage(); goto bail_out; } keyfile = bstrdup(optarg); break; case 'p': populate_cache = true; cache_file = bstrdup(optarg); break; case 's': set_encryption = true; if (keyfile) { usage(); goto bail_out; } keyfile = bstrdup(optarg); break; case 'v': volume_encryption_status = true; break; case 'w': wrapped_keys = true; wrap_keyfile = bstrdup(optarg); break; case '?': default: usage(); goto bail_out; } } argc -= optind; argv += optind; if (!generate_passphrase && !show_keydata && !populate_cache && argc < 1) { fprintf(stderr, _("Missing device_name argument for this option\n")); usage(); retval = 1; goto bail_out; } if (generate_passphrase && show_keydata) { fprintf(stderr, _("Either use -g or -k not both\n")); retval = 1; goto bail_out; } if (clear_encryption && set_encryption) { fprintf(stderr, _("Either use -c or -s not both\n")); retval = 1; goto bail_out; } if ((clear_encryption || set_encryption) && (drive_encryption_status || volume_encryption_status)) { fprintf(stderr, _("Either set or clear the crypto key or ask for status not both\n")); retval = 1; goto bail_out; } if ((clear_encryption || set_encryption || drive_encryption_status || volume_encryption_status) && (generate_passphrase || show_keydata || populate_cache)) { fprintf(stderr, _("Don't mix operations which are incompatible " "e.g. generate/show vs set/clear etc.\n")); retval = 1; goto bail_out; } OSDependentInit(); init_msg(NULL, NULL); if (populate_cache) { char *VolumeName, *EncrKey; char new_cache_entry[256]; /* * Load any keys currently in the cache. */ read_crypto_cache(cache_file); /* * Read new entries from stdin and parse them to update * the cache. */ fprintf(stdout, _("Enter cache entrie(s) (close with ^D): ")); fflush(stdout); while (read(1, new_cache_entry, sizeof(new_cache_entry)) > 0) { strip_trailing_junk(new_cache_entry); /* * Try to parse the entry. */ VolumeName = new_cache_entry; EncrKey = strchr(new_cache_entry, '\t'); if (!EncrKey) { break; } *EncrKey++ = '\0'; update_crypto_cache(VolumeName, EncrKey); } /* * Write out the new cache entries. */ write_crypto_cache(cache_file); goto bail_out; } memset(keydata, 0, sizeof(keydata)); memset(wrapdata, 0, sizeof(wrapdata)); if (wrapped_keys) { /* * Read the key bits from the keyfile. * - == stdin */ if (bstrcmp(wrap_keyfile, "-")) { kfd = 0; fprintf(stdout, _("Enter Key Encryption Key: ")); fflush(stdout); } else { kfd = open(wrap_keyfile, O_RDONLY); if (kfd < 0) { fprintf(stderr, _("Cannot open keyfile %s\n"), wrap_keyfile); retval = 1; goto bail_out; } } read(kfd, wrapdata, sizeof(wrapdata)); if (kfd > 0) { close(kfd); } strip_trailing_junk(wrapdata); Dmsg1(10, "Wrapped keydata = %s\n", wrapdata); } /* * Generate a new passphrase allow it to be wrapped using the given wrapkey * and base64 if specified or when wrapped. */ if (generate_passphrase) { int cnt; char *passphrase; passphrase = generate_crypto_passphrase(DEFAULT_PASSPHRASE_LENGTH); if (!passphrase) { retval = 1; goto bail_out; } Dmsg1(10, "Generated passphrase = %s\n", passphrase); /* * See if we need to wrap the passphrase. */ if (wrapped_keys) { char *wrapped_passphrase; length = DEFAULT_PASSPHRASE_LENGTH + 8; wrapped_passphrase = (char *)malloc(length); memset(wrapped_passphrase, 0, length); aes_wrap((unsigned char *)wrapdata, DEFAULT_PASSPHRASE_LENGTH / 8, (unsigned char *)passphrase, (unsigned char *)wrapped_passphrase); free(passphrase); passphrase = wrapped_passphrase; } else { length = DEFAULT_PASSPHRASE_LENGTH; } /* * See where to write the key. * - == stdout */ if (bstrcmp(keyfile, "-")) { kfd = 1; } else { kfd = open(keyfile, O_WRONLY | O_CREAT, 0644); if (kfd < 0) { fprintf(stderr, _("Cannot open keyfile %s\n"), keyfile); free(passphrase); retval = 1; goto bail_out; } } if (base64_transform || wrapped_keys) { cnt = bin_to_base64(keydata, sizeof(keydata), passphrase, length, true); if (write(kfd, keydata, cnt) != cnt) { fprintf(stderr, _("Failed to write %d bytes to keyfile %s\n"), cnt, keyfile); } } else { cnt = DEFAULT_PASSPHRASE_LENGTH; if (write(kfd, passphrase, cnt) != cnt) { fprintf(stderr, _("Failed to write %d bytes to keyfile %s\n"), cnt, keyfile); } } Dmsg1(10, "Keydata = %s\n", keydata); if (kfd > 1) { close(kfd); } else { write(kfd, "\n", 1); } free(passphrase); goto bail_out; } if (show_keydata) { char *passphrase; /* * Read the key bits from the keyfile. * - == stdin */ if (bstrcmp(keyfile, "-")) { kfd = 0; fprintf(stdout, _("Enter Encryption Key: ")); fflush(stdout); } else { kfd = open(keyfile, O_RDONLY); if (kfd < 0) { fprintf(stderr, _("Cannot open keyfile %s\n"), keyfile); retval = 1; goto bail_out; } } read(kfd, keydata, sizeof(keydata)); if (kfd > 0) { close(kfd); } strip_trailing_junk(keydata); Dmsg1(10, "Keydata = %s\n", keydata); /* * See if we need to unwrap the passphrase. */ if (wrapped_keys) { char *wrapped_passphrase; /* * A wrapped key is base64 encoded after it was wrapped so first * convert it from base64 to bin. As we first go from base64 to bin * and the base64_to_bin has a check if the decoded string will fit * we need to alocate some more bytes for the decoded buffer to be * sure it will fit. */ length = DEFAULT_PASSPHRASE_LENGTH + 12; wrapped_passphrase = (char *)malloc(length); memset(wrapped_passphrase, 0, length); if (base64_to_bin(wrapped_passphrase, length, keydata, strlen(keydata)) == 0) { fprintf(stderr, _("Failed to base64 decode the keydata read from %s, aborting...\n"), keyfile); free(wrapped_passphrase); goto bail_out; } length = DEFAULT_PASSPHRASE_LENGTH; passphrase = (char *)malloc(length); memset(passphrase, 0, length); if (aes_unwrap((unsigned char *)wrapdata, length / 8, (unsigned char *)wrapped_passphrase, (unsigned char *)passphrase) == -1) { fprintf(stderr, _("Failed to aes unwrap the keydata read from %s using the wrap data from %s, aborting...\n"), keyfile, wrap_keyfile); free(wrapped_passphrase); goto bail_out; } free(wrapped_passphrase); } else { if (base64_transform) { /* * As we first go from base64 to bin and the base64_to_bin has a check * if the decoded string will fit we need to alocate some more bytes * for the decoded buffer to be sure it will fit. */ length = DEFAULT_PASSPHRASE_LENGTH + 4; passphrase = (char *)malloc(length); memset(passphrase, 0, length); base64_to_bin(passphrase, length, keydata, strlen(keydata)); } else { length = DEFAULT_PASSPHRASE_LENGTH; passphrase = (char *)malloc(length); memset(passphrase, 0, length); bstrncpy(passphrase, keydata, length); } } Dmsg1(10, "Unwrapped passphrase = %s\n", passphrase); fprintf(stdout, "%s\n", passphrase); free(passphrase); goto bail_out; } /* * Clear the loaded encryption key of the given drive. */ if (clear_encryption) { if (clear_scsi_encryption_key(-1, argv[0])) { goto bail_out; } else { retval = 1; goto bail_out; } } /* * Get the drive encryption status of the given drive. */ if (drive_encryption_status) { POOLMEM *encryption_status = get_pool_memory(PM_MESSAGE); if (get_scsi_drive_encryption_status(-1, argv[0], encryption_status, 0)) { fprintf(stdout, "%s", encryption_status); free_pool_memory(encryption_status); } else { retval = 1; free_pool_memory(encryption_status); goto bail_out; } } /* * Load a new encryption key onto the given drive. */ if (set_encryption) { /* * Read the key bits from the keyfile. * - == stdin */ if (bstrcmp(keyfile, "-")) { kfd = 0; fprintf(stdout, _("Enter Encryption Key (close with ^D): ")); fflush(stdout); } else { kfd = open(keyfile, O_RDONLY); if (kfd < 0) { fprintf(stderr, _("Cannot open keyfile %s\n"), keyfile); retval = 1; goto bail_out; } } read(kfd, keydata, sizeof(keydata)); if (kfd > 0) { close(kfd); } strip_trailing_junk(keydata); if (set_scsi_encryption_key(-1, argv[0], keydata)) { goto bail_out; } else { retval = 1; goto bail_out; } } /* * Get the volume encryption status of volume currently loaded in the given drive. */ if (volume_encryption_status) { POOLMEM *encryption_status = get_pool_memory(PM_MESSAGE); if (get_scsi_volume_encryption_status(-1, argv[0], encryption_status, 0)) { fprintf(stdout, "%s", encryption_status); free_pool_memory(encryption_status); } else { retval = 1; free_pool_memory(encryption_status); goto bail_out; } } bail_out: if (cache_file) { free(cache_file); } if (keyfile) { free(keyfile); } if (wrap_keyfile) { free(wrap_keyfile); } exit(retval); }
/* This function is a modified version of the one found in bacula in src/lib/cram-md5.c */ int authenticate_monitor(monitor * mon) { char hello[] = "Hello *UserAgent* calling\n"; int tls, compatible, err; /* Send the initial hello message */ err = send_message(mon, hello, strlen(hello)); if(err != E_SUCCESS) { return err; } /* Get the cram challenge and respond */ { char resp[MAXSTRING]; char chal[MAXSTRING]; char msg[MAXSTRING]; uint8_t hmac[20]; size_t len; err = receive_message(mon, resp, MAXSTRING); if(err < E_SUCCESS) { return err; } compatible = 0; if(sscanf(resp, "auth cram-md5c %s ssl=%d", chal, &tls) == 2) { compatible = 1; } else if(sscanf(resp, "auth cram-md5 %s ssl=%d", chal, &tls) != 2) { if(sscanf(resp, "auth cram-md5 %s\n", chal) != 1) { return E_MONITOR_BAD_SCAN_CHALLENGE; } } hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)mon->passwd, strlen(mon->passwd), hmac); len = bin_to_base64(msg, 50, (char *)hmac, 16, compatible) + 1; err = send_message(mon, msg, len); if(err != E_SUCCESS) { return err; } err = receive_message(mon, resp, MAXSTRING); if(err < E_SUCCESS) { return err; } if(strcmp(resp, "1000 OK auth\n") != 0) { return E_MONITOR_AUTH_FAILED; } } /* send our cram challenge */ { int i; struct timeval t1; struct timeval t2; struct timezone tz; char chal[MAXSTRING]; gettimeofday(&t1, &tz); for(i = 0; i < 4; ++i) { gettimeofday(&t2, &tz); } srandom((t1.tv_sec&0xffff) * (t2.tv_usec&0xff)); snprintf(chal, sizeof(chal), "auth cram-md5 <%u.%u@%s> ssl=0\n", (uint32_t)random(), (uint32_t)time(NULL), mon->host_name); } /* err = receive_message(mon, resp, MAXSTRING); if(err != E_SUCCESS) { return err; } */ return E_SUCCESS; }
/* * Called here by find() for each file. * * Find the file, compute the MD5 or SHA1 and send it back to the Director */ static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level) { POOL_MEM attribs(PM_NAME), attribsEx(PM_NAME); int digest_stream = STREAM_NONE; int status; DIGEST *digest = NULL; BSOCK *dir; if (job_canceled(jcr)) { return 0; } dir = jcr->dir_bsock; jcr->num_files_examined++; /* bump total file count */ switch (ff_pkt->type) { case FT_LNKSAVED: /* Hard linked, file already saved */ Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link); break; case FT_REGE: Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname); break; case FT_REG: Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname); break; case FT_LNK: Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link); break; case FT_DIRBEGIN: jcr->num_files_examined--; /* correct file count */ return 1; /* ignored */ case FT_REPARSE: case FT_JUNCTION: case FT_DIREND: Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname); break; case FT_SPEC: Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname); break; case FT_RAW: Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname); break; case FT_FIFO: Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname); break; case FT_NOACCESS: { berrno be; be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 1, _(" Could not access %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; return 1; } case FT_NOFOLLOW: { berrno be; be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 1, _(" Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; return 1; } case FT_NOSTAT: { berrno be; be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 1, _(" Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; return 1; } case FT_DIRNOCHG: case FT_NOCHG: Jmsg(jcr, M_SKIPPED, 1, _(" Unchanged file skipped: %s\n"), ff_pkt->fname); return 1; case FT_ISARCH: Jmsg(jcr, M_SKIPPED, 1, _(" Archive file skipped: %s\n"), ff_pkt->fname); return 1; case FT_NORECURSE: Jmsg(jcr, M_SKIPPED, 1, _(" Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname); ff_pkt->type = FT_DIREND; /* directory entry was backed up */ break; case FT_NOFSCHG: Jmsg(jcr, M_SKIPPED, 1, _(" File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname); return 1; case FT_PLUGIN_CONFIG: case FT_RESTORE_FIRST: return 1; /* silently skip */ case FT_NOOPEN: { berrno be; be.set_errno(ff_pkt->ff_errno); Jmsg(jcr, M_NOTSAVED, 1, _(" Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.bstrerror()); jcr->JobErrors++; return 1; } default: Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname); jcr->JobErrors++; return 1; } /* Encode attributes and possibly extend them */ encode_stat(attribs.c_str(), &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, 0); encode_attribsEx(jcr, attribsEx.c_str(), ff_pkt); jcr->lock(); jcr->JobFiles++; /* increment number of files sent */ pm_strcpy(jcr->last_fname, ff_pkt->fname); jcr->unlock(); /* * Send file attributes to Director * File_index * Stream * Verify Options * Filename (full path) * Encoded attributes * Link name (if type==FT_LNK) * For a directory, link is the same as fname, but with trailing * slash. For a linked file, link is the link. */ /* Send file attributes to Director (note different format than for Storage) */ Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname); if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) { status = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, 0, attribs.c_str(), 0, ff_pkt->link, 0); } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION) { /* Here link is the canonical filename (i.e. with trailing slash) */ status = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link, 0, attribs.c_str(), 0, 0); } else { status = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, 0, attribs.c_str(), 0, 0); } Dmsg2(20, "filed>dir: attribs len=%d: msg=%s\n", dir->msglen, dir->msg); if (!status) { Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir)); return 0; } /* * The remainder of the function is all about getting the checksum. * First we initialise, then we read files, other streams and Finder Info. */ if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) && ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) { /* * Create our digest context. If this fails, the digest will be set to NULL * and not used. */ if (ff_pkt->flags & FO_MD5) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5); digest_stream = STREAM_MD5_DIGEST; } else if (ff_pkt->flags & FO_SHA1) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1); digest_stream = STREAM_SHA1_DIGEST; } else if (ff_pkt->flags & FO_SHA256) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256); digest_stream = STREAM_SHA256_DIGEST; } else if (ff_pkt->flags & FO_SHA512) { digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512); digest_stream = STREAM_SHA512_DIGEST; } /* Did digest initialization fail? */ if (digest_stream != STREAM_NONE && digest == NULL) { Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"), stream_to_ascii(digest_stream)); } /* compute MD5 or SHA1 hash */ if (digest) { char md[CRYPTO_DIGEST_MAX_SIZE]; uint32_t size; size = sizeof(md); if (digest_file(jcr, ff_pkt, digest) != 0) { jcr->JobErrors++; goto good_rtn; } if (crypto_digest_finalize(digest, (uint8_t *)md, &size)) { char *digest_buf; const char *digest_name; digest_buf = (char *)malloc(BASE64_SIZE(size)); digest_name = crypto_digest_name(digest); bin_to_base64(digest_buf, BASE64_SIZE(size), md, size, true); Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, digest_name, digest_buf); dir->fsend("%d %d %s *%s-%d*", jcr->JobFiles, digest_stream, digest_buf, digest_name, jcr->JobFiles); Dmsg3(20, "filed>dir: %s len=%d: msg=%s\n", digest_name, dir->msglen, dir->msg); free(digest_buf); } } } good_rtn: if (digest) { crypto_digest_free(digest); } return 1; }
ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey, const char *passphrase, ssh_auth_callback auth_fn, void *auth_data) { ssh_buffer buffer; ssh_string str = NULL; ssh_string pubkey_s=NULL; ssh_buffer privkey_buffer = NULL; uint32_t rnd; uint32_t rounds = 16; ssh_string salt=NULL; ssh_string kdf_options=NULL; int to_encrypt=0; unsigned char *b64; uint32_t str_len, len; int rc; if (privkey == NULL) { return NULL; } if (privkey->type != SSH_KEYTYPE_ED25519){ ssh_pki_log("Unsupported key type %s", privkey->type_c); return NULL; } if (passphrase != NULL || auth_fn != NULL){ ssh_pki_log("Enabling encryption for private key export"); to_encrypt = 1; } buffer = ssh_buffer_new(); pubkey_s = pki_publickey_to_blob(privkey); if(buffer == NULL || pubkey_s == NULL){ goto error; } ssh_get_random(&rnd, sizeof(rnd), 0); privkey_buffer = ssh_buffer_new(); if (privkey_buffer == NULL) { goto error; } /* checkint1 & 2 */ rc = ssh_buffer_pack(privkey_buffer, "dd", rnd, rnd); if (rc == SSH_ERROR){ goto error; } rc = pki_openssh_export_privkey_blob(privkey, privkey_buffer); if (rc == SSH_ERROR){ goto error; } /* comment */ rc = ssh_buffer_pack(privkey_buffer, "s", "" /* comment */); if (rc == SSH_ERROR){ goto error; } if (to_encrypt){ ssh_buffer kdf_buf; kdf_buf = ssh_buffer_new(); if (kdf_buf == NULL) { goto error; } salt = ssh_string_new(16); if (salt == NULL){ ssh_buffer_free(kdf_buf); goto error; } ssh_get_random(ssh_string_data(salt),16, 0); ssh_buffer_pack(kdf_buf, "Sd", salt, rounds); kdf_options = ssh_string_new(ssh_buffer_get_len(kdf_buf)); if (kdf_options == NULL){ ssh_buffer_free(kdf_buf); goto error; } memcpy(ssh_string_data(kdf_options), ssh_buffer_get_begin(kdf_buf), ssh_buffer_get_len(kdf_buf)); ssh_buffer_free(kdf_buf); rc = pki_private_key_encrypt(privkey_buffer, passphrase, "aes128-cbc", "bcrypt", auth_fn, auth_data, rounds, salt); if (rc != SSH_OK){ goto error; } } else { kdf_options = ssh_string_new(0); } rc = ssh_buffer_pack(buffer, "PssSdSdP", (size_t)strlen(OPENSSH_AUTH_MAGIC) + 1, OPENSSH_AUTH_MAGIC, to_encrypt ? "aes128-cbc" : "none", /* ciphername */ to_encrypt ? "bcrypt" : "none", /* kdfname */ kdf_options, /* kdfoptions */ (uint32_t) 1, /* nkeys */ pubkey_s, (uint32_t)ssh_buffer_get_len(privkey_buffer), /* rest of buffer is a string */ (size_t)ssh_buffer_get_len(privkey_buffer), ssh_buffer_get_begin(privkey_buffer)); if (rc != SSH_OK) { goto error; } b64 = bin_to_base64(ssh_buffer_get_begin(buffer), ssh_buffer_get_len(buffer)); if (b64 == NULL){ goto error; } /* we can reuse the buffer */ ssh_buffer_reinit(buffer); rc = ssh_buffer_pack(buffer, "tttttt", OPENSSH_HEADER_BEGIN, "\n", b64, "\n", OPENSSH_HEADER_END, "\n"); BURN_BUFFER(b64, strlen((char *)b64)); SAFE_FREE(b64); if (rc != SSH_OK){ goto error; } str = ssh_string_new(ssh_buffer_get_len(buffer)); if (str == NULL){ goto error; } str_len = ssh_buffer_get_len(buffer); len = buffer_get_data(buffer, ssh_string_data(str), str_len); if (str_len != len) { ssh_string_free(str); str = NULL; } error: if (privkey_buffer != NULL) { void *bufptr = ssh_buffer_get_begin(privkey_buffer); BURN_BUFFER(bufptr, ssh_buffer_get_len(privkey_buffer)); ssh_buffer_free(privkey_buffer); } SAFE_FREE(pubkey_s); SAFE_FREE(kdf_options); SAFE_FREE(salt); if (buffer != NULL) { ssh_buffer_free(buffer); } return str; }
void test_base64(void **state) { (void) state; /* unused */ /* * Test the base64 routines by encoding and decoding * lstat() packets. */ char where[500]; int i; char *fname; struct stat statp; struct stat statn; int debug_level = 0; char *p; int32_t j; time_t t = 1028712799; fname = BINARYNAME; base64_init(); if (lstat(fname, &statp) < 0) { berrno be; printf("Cannot stat %s: %s\n", fname, be.bstrerror(errno)); } encode_stat(where, &statp, sizeof(statp), 0, 0); //printf("Encoded stat=%s\n", where); #ifdef xxx p = where; p += to_base64((int64_t)(statp.st_atime), p); *p++ = ' '; p += to_base64((int64_t)t, p); printf("%s %s\n", fname, where); printf("%s %lld\n", "st_dev", (int64_t)statp.st_dev); printf("%s %lld\n", "st_ino", (int64_t)statp.st_ino); printf("%s %lld\n", "st_mode", (int64_t)statp.st_mode); printf("%s %lld\n", "st_nlink", (int64_t)statp.st_nlink); printf("%s %lld\n", "st_uid", (int64_t)statp.st_uid); printf("%s %lld\n", "st_gid", (int64_t)statp.st_gid); printf("%s %lld\n", "st_rdev", (int64_t)statp.st_rdev); printf("%s %lld\n", "st_size", (int64_t)statp.st_size); printf("%s %lld\n", "st_blksize", (int64_t)statp.st_blksize); printf("%s %lld\n", "st_blocks", (int64_t)statp.st_blocks); printf("%s %lld\n", "st_atime", (int64_t)statp.st_atime); printf("%s %lld\n", "st_mtime", (int64_t)statp.st_mtime); printf("%s %lld\n", "st_ctime", (int64_t)statp.st_ctime); #endif //printf("%s: len=%d val=%s\n", fname, strlen(where), where); decode_stat(where, &statn, sizeof(statn), &j); assert_false(statp.st_dev != statn.st_dev || statp.st_ino != statn.st_ino || statp.st_mode != statn.st_mode || statp.st_nlink != statn.st_nlink || statp.st_uid != statn.st_uid || statp.st_gid != statn.st_gid || statp.st_rdev != statn.st_rdev || statp.st_size != statn.st_size || statp.st_blksize != statn.st_blksize || statp.st_blocks != statn.st_blocks || statp.st_atime != statn.st_atime || statp.st_mtime != statn.st_mtime || statp.st_ctime != statn.st_ctime); /* { printf("%s: %s\n", fname, where); encode_stat(where, &statn, sizeof(statn), 0, 0); printf("%s: %s\n", fname, where); printf("NOT EQAL\n"); } */ //printf("%d files examined\n", i); to_base64(UINT32_MAX, where); //printf("UINT32_MAX=%s\n", where); int xx = 0; int len; char buf[100]; char junk[100]; // int i; #ifdef xxxx for (i=0; i < 1000; i++) { bin_to_base64(buf, sizeof(buf), (char *)&xx, 4, true); printf("xx=%s\n", buf); xx++; } #endif junk[0] = 0xFF; for (i=1; i<100; i++) { junk[i] = junk[i-1]-1; } len = bin_to_base64(buf, sizeof(buf), junk, 16, true); //printf("len=%d junk=%s\n", len, buf); strcpy(junk, "This is a sample string"); len = bin_to_base64(buf, sizeof(buf), junk, strlen(junk), true); buf[len] = 0; base64_to_bin(junk, sizeof(junk), buf, len); //printf("buf=<%s>\n", junk); }