static void test_sparse_files_8(void) { Log(LOG_LEVEL_VERBOSE, "Special Case: File ending with few (DEV_BSIZE-1) zeroes," " at block size barrier; so the last bytes written are a hole and are seek()ed," " but the output file can't be sparse since the hole isn't block-sized"); char *buf = xmalloc(TESTFILE_SIZE + DEV_BSIZE - 1); FillBufferWithGarbage(buf, TESTFILE_SIZE); memset(&buf[TESTFILE_SIZE], 0, DEV_BSIZE - 1); WriteBufferToFile(srcfile, buf, TESTFILE_SIZE + DEV_BSIZE - 1); /* ACTUAL TEST */ bool ret = CopyRegularFileDisk(srcfile, dstfile); assert_true(ret); if (SPARSE_SUPPORT_OK) { bool is_sparse = FileIsSparse(dstfile); assert_false(is_sparse); } bool data_ok = CompareFileToBuffer(dstfile, buf, TESTFILE_SIZE + DEV_BSIZE - 1); assert_true(data_ok); free(buf); test_has_run[8] = true; success [8] = true; }
static void test_sparse_files_7(void) { Log(LOG_LEVEL_VERBOSE, "File ending with many zeroes, the output file must be sparse"); char *buf = xmalloc(TESTFILE_SIZE); FillBufferWithGarbage(buf, TESTFILE_SIZE); memset(&buf[TESTFILE_SIZE - LONG_REGION], 0, LONG_REGION); WriteBufferToFile(srcfile, buf, TESTFILE_SIZE); /* ACTUAL TEST */ bool ret = CopyRegularFileDisk(srcfile, dstfile); assert_true(ret); if (SPARSE_SUPPORT_OK) { bool is_sparse = FileIsSparse(dstfile); assert_true(is_sparse); } bool data_ok = CompareFileToBuffer(dstfile, buf, TESTFILE_SIZE); assert_true(data_ok); free(buf); test_has_run[7] = true; success [7] = true; }
static void test_sparse_files_1(void) { Log(LOG_LEVEL_VERBOSE, "No zeros in the file, the output file must be non-sparse"); char *buf = xmalloc(TESTFILE_SIZE); FillBufferWithGarbage(buf, TESTFILE_SIZE); WriteBufferToFile(srcfile, buf, TESTFILE_SIZE); /* ACTUAL TEST */ bool ret = CopyRegularFileDisk(srcfile, dstfile); assert_true(ret); if (SPARSE_SUPPORT_OK) { bool is_sparse = FileIsSparse(dstfile); assert_false(is_sparse); } bool data_ok = CompareFileToBuffer(dstfile, buf, TESTFILE_SIZE); assert_true(data_ok); free(buf); test_has_run[1] = true; success [1] = true; }
int ArchiveToRepository(const char *file, Attributes attr, Promise *pp, const ReportContext *report_context) /* Returns true if the file was backup up and false if not */ { char destination[CF_BUFSIZE]; struct stat sb, dsb; if (!GetRepositoryPath(file, attr, destination)) { return false; } if (attr.copy.backup == cfa_nobackup) { return true; } if (IsItemIn(VREPOSLIST, file)) { CfOut(OUTPUT_LEVEL_INFORM, "", "The file %s has already been moved to the repository once. Multiple update will cause loss of backup.", file); return true; } ThreadLock(cft_getaddr); PrependItemList(&VREPOSLIST, file); ThreadUnlock(cft_getaddr); CfDebug("Repository(%s)\n", file); JoinPath(destination, CanonifyName(file)); if (!MakeParentDirectory(destination, attr.move_obstructions, report_context)) { } if (cfstat(file, &sb) == -1) { CfDebug("File %s promised to archive to the repository but it disappeared!\n", file); return true; } cfstat(destination, &dsb); CheckForFileHoles(&sb, pp); if (pp && CopyRegularFileDisk(file, destination, pp->makeholes)) { CfOut(OUTPUT_LEVEL_INFORM, "", "Moved %s to repository location %s\n", file, destination); return true; } else { CfOut(OUTPUT_LEVEL_INFORM, "", "Failed to move %s to repository location %s\n", file, destination); return false; } }
int ArchiveToRepository(const char *file, Attributes attr) /* Returns true if the file was backup up and false if not */ { char destination[CF_BUFSIZE]; struct stat sb, dsb; if (!GetRepositoryPath(file, attr, destination)) { return false; } if (attr.copy.backup == BACKUP_OPTION_NO_BACKUP) { return true; } if (IsItemIn(VREPOSLIST, file)) { Log(LOG_LEVEL_INFO, "The file '%s' has already been moved to the repository once. Multiple update will cause loss of backup.", file); return true; } ThreadLock(cft_getaddr); PrependItemList(&VREPOSLIST, file); ThreadUnlock(cft_getaddr); JoinPath(destination, CanonifyName(file)); if (!MakeParentDirectory(destination, attr.move_obstructions)) { } if (stat(file, &sb) == -1) { Log(LOG_LEVEL_DEBUG, "File '%s' promised to archive to the repository but it disappeared!", file); return true; } stat(destination, &dsb); if (CopyRegularFileDisk(file, destination)) { Log(LOG_LEVEL_INFO, "Moved '%s' to repository location '%s'", file, destination); return true; } else { Log(LOG_LEVEL_INFO, "Failed to move '%s' to repository location '%s'", file, destination); return false; } }
int TrustKey(const char* pubkey) { char *digeststr = GetPubkeyDigest(pubkey); char outfilename[CF_BUFSIZE]; bool ok; if (NULL == digeststr) return 1; /* ERROR exitcode */ snprintf(outfilename, CF_BUFSIZE, "%s/ppkeys/root-%s.pub", CFWORKDIR, digeststr); free(digeststr); ok = CopyRegularFileDisk(pubkey, outfilename); return (ok? 0 : 1); }
/** * @brief removes all traces of entry 'input' from lastseen and filesystem * * @param[in] key digest (SHA/MD5 format) or free host name string * @param[in] must_be_coherent. false : delete if lastseen is incoherent, * true : don't if lastseen is incoherent * @retval 0 if entry was deleted, >0 otherwise */ int RemoveKeys(const char *input, bool must_be_coherent) { int res = 0; char equivalent[CF_BUFSIZE]; equivalent[0] = '\0'; res = RemoveKeysFromLastSeen(input, must_be_coherent, equivalent); if (res!=0) { return res; } Log(LOG_LEVEL_INFO, "Removed corresponding entries from lastseen database."); int removed_input = RemovePublicKey(input); int removed_equivalent = RemovePublicKey(equivalent); if ((removed_input == -1) || (removed_equivalent == -1)) { Log(LOG_LEVEL_ERR, "Unable to remove keys for the entry %s", input); return 255; } else if (removed_input + removed_equivalent == 0) { Log(LOG_LEVEL_ERR, "No key file(s) for entry %s were found on the filesytem", input); return 1; } else { Log(LOG_LEVEL_INFO, "Removed %d corresponding key file(s) from filesystem.", removed_input + removed_equivalent); return 0; } return -1; } void KeepKeyPromises(const char *public_key_file, const char *private_key_file) { unsigned long err; #ifdef OPENSSL_NO_DEPRECATED RSA *pair = RSA_new(); BIGNUM *rsa_bignum = BN_new(); #else RSA *pair; #endif FILE *fp; struct stat statbuf; int fd; static char *passphrase = "Cfengine passphrase"; const EVP_CIPHER *cipher; char vbuff[CF_BUFSIZE]; cipher = EVP_des_ede3_cbc(); if (stat(public_key_file, &statbuf) != -1) { printf("A key file already exists at %s\n", public_key_file); return; } if (stat(private_key_file, &statbuf) != -1) { printf("A key file already exists at %s\n", private_key_file); return; } printf("Making a key pair for cfengine, please wait, this could take a minute...\n"); #ifdef OPENSSL_NO_DEPRECATED BN_set_word(rsa_bignum, 35); if (!RSA_generate_key_ex(pair, 2048, rsa_bignum, NULL)) #else pair = RSA_generate_key(2048, 35, NULL, NULL); if (pair == NULL) #endif { err = ERR_get_error(); Log(LOG_LEVEL_ERR, "Unable to generate key '%s'", ERR_reason_error_string(err)); return; } fd = open(private_key_file, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) { Log(LOG_LEVEL_ERR, "Open '%s' failed. (open: %s)", private_key_file, GetErrorStr()); return; } if ((fp = fdopen(fd, "w")) == NULL) { Log(LOG_LEVEL_ERR, "Couldn't open private key '%s'. (fdopen: %s)", private_key_file, GetErrorStr()); close(fd); return; } Log(LOG_LEVEL_VERBOSE, "Writing private key to '%s'", private_key_file); if (!PEM_write_RSAPrivateKey(fp, pair, cipher, passphrase, strlen(passphrase), NULL, NULL)) { err = ERR_get_error(); Log(LOG_LEVEL_ERR, "Couldn't write private key. (PEM_write_RSAPrivateKey: %s)", ERR_reason_error_string(err)); return; } fclose(fp); fd = open(public_key_file, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) { Log(LOG_LEVEL_ERR, "Unable to open public key '%s'. (open: %s)", public_key_file, GetErrorStr()); return; } if ((fp = fdopen(fd, "w")) == NULL) { Log(LOG_LEVEL_ERR, "Open '%s' failed. (fdopen: %s)", public_key_file, GetErrorStr()); close(fd); return; } Log(LOG_LEVEL_VERBOSE, "Writing public key to file '%s'", public_key_file); if (!PEM_write_RSAPublicKey(fp, pair)) { err = ERR_get_error(); Log(LOG_LEVEL_ERR, "Unable to write public key. (PEM_write_RSAPublicKey: %s)", ERR_reason_error_string(err)); return; } fclose(fp); snprintf(vbuff, CF_BUFSIZE, "%s/randseed", CFWORKDIR); RAND_write_file(vbuff); chmod(vbuff, 0644); } #ifndef HAVE_NOVA bool LicenseInstall(ARG_UNUSED char *path_source) { Log(LOG_LEVEL_ERR, "License installation only applies to CFEngine Enterprise"); return false; } #else /* HAVE_NOVA */ bool LicenseInstall(char *path_source) { struct stat sb; if(stat(path_source, &sb) == -1) { Log(LOG_LEVEL_ERR, "Can not stat input license file '%s'. (stat: %s)", path_source, GetErrorStr()); return false; } char path_destination[MAX_FILENAME]; snprintf(path_destination, sizeof(path_destination), "%s/inputs/license.dat", CFWORKDIR); MapName(path_destination); if(stat(path_destination, &sb) == 0) { Log(LOG_LEVEL_ERR, "A license file is already installed in '%s' -- please move it out of the way and try again", path_destination); return false; } char path_public_key[MAX_FILENAME]; if(!LicensePublicKeyPath(path_public_key, path_source)) { Log(LOG_LEVEL_ERR, "Could not find path to public key -- license parse error?"); } if(stat(path_public_key, &sb) != 0) { Log(LOG_LEVEL_ERR, "The licensed public key is not installed -- please copy it to '%s' and try again", path_public_key); return false; } bool success = CopyRegularFileDisk(path_source, path_destination); if(success) { Log(LOG_LEVEL_INFO, "Installed license at '%s'", path_destination); } else { Log(LOG_LEVEL_ERR, "Failed copying license from '%s' to '%s'", path_source, path_destination); } return success; }
bool CopyRegularFileDiskReport(char *source, char *destination, Attributes attr, Promise *pp) // TODO: return error codes in CopyRegularFileDisk and print them to cfPS here { bool make_holes = false; if(pp && pp->makeholes) { make_holes = true; } bool result = CopyRegularFileDisk(source, destination, make_holes); if(!result) { cfPS(cf_inform, CF_FAIL, "", pp, attr, "Failed copying file %s to %s", source, destination); } return result; }
static bool ChangePasswordHashUsingLckpwdf(const char *puser, const char *password) { bool result = false; struct stat statbuf; const char *passwd_file = "/etc/shadow"; if (stat(passwd_file, &statbuf) == -1) { passwd_file = "/etc/passwd"; } Log(LOG_LEVEL_VERBOSE, "Changing password hash for user '%s' by editing '%s'.", puser, passwd_file); if (lckpwdf() != 0) { Log(LOG_LEVEL_ERR, "Not able to obtain lock on password database."); return false; } char backup_file[strlen(passwd_file) + strlen(".cf-backup") + 1]; xsnprintf(backup_file, sizeof(backup_file), "%s.cf-backup", passwd_file); unlink(backup_file); char edit_file[strlen(passwd_file) + strlen(".cf-edit") + 1]; xsnprintf(edit_file, sizeof(edit_file), "%s.cf-edit", passwd_file); unlink(edit_file); if (!CopyRegularFileDisk(passwd_file, backup_file)) { Log(LOG_LEVEL_ERR, "Could not back up existing password database '%s' to '%s'.", passwd_file, backup_file); goto unlock_passwd; } FILE *passwd_fd = fopen(passwd_file, "r"); if (!passwd_fd) { Log(LOG_LEVEL_ERR, "Could not open password database '%s'. (fopen: '%s')", passwd_file, GetErrorStr()); goto unlock_passwd; } int edit_fd_int = open(edit_file, O_WRONLY | O_CREAT | O_EXCL, S_IWUSR); if (edit_fd_int < 0) { if (errno == EEXIST) { Log(LOG_LEVEL_CRIT, "Temporary file already existed when trying to open '%s'. (open: '%s') " "This should NEVER happen and could mean that someone is trying to break into your system!!", edit_file, GetErrorStr()); } else { Log(LOG_LEVEL_ERR, "Could not open password database temporary file '%s'. (open: '%s')", edit_file, GetErrorStr()); } goto close_passwd_fd; } FILE *edit_fd = fdopen(edit_fd_int, "w"); if (!edit_fd) { Log(LOG_LEVEL_ERR, "Could not open password database temporary file '%s'. (fopen: '%s')", edit_file, GetErrorStr()); close(edit_fd_int); goto close_passwd_fd; } while (true) { size_t line_size = 0; char *line = NULL; int read_result = CfReadLine(&line, &line_size, passwd_fd); if (read_result < 0) { if (!feof(passwd_fd)) { Log(LOG_LEVEL_ERR, "Error while reading password database: %s", GetErrorStr()); free(line); goto close_both; } else { break; } } // Editing the password database is risky business, so do as little parsing as possible. // Just enough to get the hash in there. char *field_start = NULL; char *field_end = NULL; field_start = strchr(line, ':'); if (field_start) { field_end = strchr(field_start + 1, ':'); } if (!field_start || !field_end) { Log(LOG_LEVEL_ERR, "Unexpected format found in password database while editing user '%s'. Not updating.", puser); free(line); goto close_both; } // Worst case length: Existing password is empty plus one '\n' and one '\0'. char new_line[strlen(line) + strlen(password) + 2]; *field_start = '\0'; *field_end = '\0'; if (strcmp(line, puser) == 0) { xsnprintf(new_line, sizeof(new_line), "%s:%s:%s\n", line, password, field_end + 1); } else { xsnprintf(new_line, sizeof(new_line), "%s:%s:%s\n", line, field_start + 1, field_end + 1); } free(line); size_t new_line_size = strlen(new_line); size_t written_so_far = 0; while (written_so_far < new_line_size) { clearerr(edit_fd); size_t written = fwrite(new_line, 1, new_line_size, edit_fd); if (written == 0) { const char *err_str; if (ferror(edit_fd)) { err_str = GetErrorStr(); } else { err_str = "Unknown error"; } Log(LOG_LEVEL_ERR, "Error while writing to file '%s'. (fwrite: '%s')", edit_file, err_str); goto close_both; } written_so_far += written; } } fclose(edit_fd); fclose(passwd_fd); if (!CopyFilePermissionsDisk(passwd_file, edit_file)) { Log(LOG_LEVEL_ERR, "Could not copy permissions from '%s' to '%s'", passwd_file, edit_file); goto unlock_passwd; } if (rename(edit_file, passwd_file) < 0) { Log(LOG_LEVEL_ERR, "Could not replace '%s' with edited password database '%s'. (rename: '%s')", passwd_file, edit_file, GetErrorStr()); goto unlock_passwd; } result = true; goto unlock_passwd; close_both: fclose(edit_fd); unlink(edit_file); close_passwd_fd: fclose(passwd_fd); unlock_passwd: ulckpwdf(); return result; }
int ArchiveToRepository(char *file,struct Attributes attr,struct Promise *pp) /* Returns true if the file was backup up and false if not */ { char destination[CF_BUFSIZE]; char localrepository[CF_BUFSIZE]; char node[CF_BUFSIZE]; struct stat sb, dsb; char *sp; if (attr.repository == NULL && VREPOSITORY == NULL) { return false; } if (attr.repository != NULL) { strncpy(localrepository,attr.repository,CF_BUFSIZE); } else if (VREPOSITORY != NULL) { strncpy(localrepository,VREPOSITORY,CF_BUFSIZE); } if (attr.copy.backup == cfa_nobackup) { return true; } if (IsItemIn(VREPOSLIST,file)) { CfOut(cf_inform,"","The file %s has already been moved to the repository once. Multiple update will cause loss of backup.",file); return true; } ThreadLock(cft_getaddr); PrependItemList(&VREPOSLIST,file); ThreadUnlock(cft_getaddr); Debug("Repository(%s)\n",file); strcpy (node,file); destination[0] = '\0'; for (sp = node; *sp != '\0'; sp++) { if (*sp == FILE_SEPARATOR) { *sp = REPOSCHAR; } } strncpy(destination,localrepository,CF_BUFSIZE-2); if (!JoinPath(destination,node)) { CfOut(cf_error,"","Internal limit: Buffer ran out of space for long filename\n"); return false; } if (!MakeParentDirectory(destination,attr.move_obstructions)) { } if (cfstat(file,&sb) == -1) { Debug("File %s promised to archive to the repository but it disappeared!\n",file); return true; } cfstat(destination,&dsb); attr.copy.servers = NULL; attr.copy.backup = cfa_repos_store; // cfa_nobackup; attr.copy.stealth = false; attr.copy.verify = false; attr.copy.preserve = false; CheckForFileHoles(&sb,pp); if (CopyRegularFileDisk(file,destination,attr,pp)) { CfOut(cf_inform,"","Moved %s to repository location %s\n",file,destination); return true; } else { CfOut(cf_inform,"","Failed to move %s to repository location %s\n",file,destination); return false; } }
void RotateFiles(char *name, int number) { int i, fd; struct stat statbuf; char from[CF_BUFSIZE], to[CF_BUFSIZE]; if (IsItemIn(ROTATED, name)) { return; } PrependItem(&ROTATED, name, NULL); if (stat(name, &statbuf) == -1) { Log(LOG_LEVEL_VERBOSE, "No access to file %s", name); return; } for (i = number - 1; i > 0; i--) { snprintf(from, CF_BUFSIZE, "%s.%d", name, i); snprintf(to, CF_BUFSIZE, "%s.%d", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } snprintf(from, CF_BUFSIZE, "%s.%d.gz", name, i); snprintf(to, CF_BUFSIZE, "%s.%d.gz", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } snprintf(from, CF_BUFSIZE, "%s.%d.Z", name, i); snprintf(to, CF_BUFSIZE, "%s.%d.Z", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } snprintf(from, CF_BUFSIZE, "%s.%d.bz", name, i); snprintf(to, CF_BUFSIZE, "%s.%d.bz", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } snprintf(from, CF_BUFSIZE, "%s.%d.bz2", name, i); snprintf(to, CF_BUFSIZE, "%s.%d.bz2", name, i + 1); if (rename(from, to) == -1) { Log(LOG_LEVEL_DEBUG, "Rename failed in RotateFiles '%s' -> '%s'", name, from); } } snprintf(to, CF_BUFSIZE, "%s.1", name); if (CopyRegularFileDisk(name, to) == false) { Log(LOG_LEVEL_DEBUG, "Copy failed in RotateFiles '%s' -> '%s'", name, to); return; } safe_chmod(to, statbuf.st_mode); if (safe_chown(to, statbuf.st_uid, statbuf.st_gid)) { UnexpectedError("Failed to chown %s", to); } safe_chmod(name, 0600); /* File must be writable to empty .. */ if ((fd = safe_creat(name, statbuf.st_mode)) == -1) { Log(LOG_LEVEL_ERR, "Failed to create new '%s' in disable(rotate). (creat: %s)", name, GetErrorStr()); } else { if (safe_chown(name, statbuf.st_uid, statbuf.st_gid)) /* NT doesn't have fchown */ { UnexpectedError("Failed to chown '%s'", name); } fchmod(fd, statbuf.st_mode); close(fd); } }