<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2011, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/



#include "condor_common.h"
#include "condor_io.h"
#include "condor_debug.h"
#include "daemon.h"
#include "condor_uid.h"
#include "lsa_mgr.h"
#include "store_cred.h"
#include "condor_config.h"
#include "ipv6_hostname.h"

static int code_store_cred(Stream *socket, char* &user, char* &pw, int &mode);

#ifndef WIN32
	// **** UNIX CODE *****

void SecureZeroMemory(void *p, size_t n)
{
	// TODO: make this Secure
	memset(p, 0, n);
}

// trivial scramble on password file to prevent accidental viewing
// NOTE: its up to the caller to ensure scrambled has enough room
void simple_scramble(char* scrambled,  const char* orig, int len)
{
	const unsigned char deadbeef[] = {0xDE, 0xAD, 0xBE, 0xEF};

	for (int i = 0; i < len; i++) {
		scrambled[i] = orig[i] ^ deadbeef[i % sizeof(deadbeef)];
	}
}

// writes a pool password file using the given password
// returns SUCCESS or FAILURE
//
int write_password_file(const char* path, const char* password)
{
	size_t password_len = strlen(password);
	char scrambled_password[MAX_PASSWORD_LENGTH + 1];
	memset(scrambled_password, 0, MAX_PASSWORD_LENGTH + 1);
	simple_scramble(scrambled_password, password, password_len);
	return secure_write_file(path, scrambled_password, MAX_PASSWORD_LENGTH + 1);
}


// writes data of length len securely to file specified in path
// returns SUCCESS or FAILURE
//
int secure_write_file(const char* path, const char* data, size_t len)
{
		int fd = safe_open_wrapper_follow(path,
		                           O_WRONLY | O_CREAT | O_TRUNC,
		                           0600);
		if (fd == -1) {
			dprintf(D_ALWAYS,
			        "secure_write_file: open failed on %s: %s (%d)\n",
			        path,
			        strerror(errno),
					errno);
			return FAILURE;
		}
		FILE *fp = fdopen(fd, "w");
		if (fp == NULL) {
			dprintf(D_ALWAYS,
			        "secure_write_file: fdopen failed: %s (%d)\n",
			        strerror(errno),
			        errno);
			return FAILURE;
		}
		size_t sz = fwrite(data, 1, len, fp);
		int save_errno = errno;
		fclose(fp);
		if (sz != len) {
			dprintf(D_ALWAYS,
			        "secure_write_file: "
			            "error writing to file: %s (%d)\n",
					strerror(save_errno),
			        save_errno);
			return FAILURE;
		}
		return SUCCESS;
}

int ZKM_UNIX_STORE_CRED(const char *user, const int len, const char *pw, int mode) {
	dprintf(D_ALWAYS, "ZKM: store cred user %s len %i mode %i contents: {%s}\n", user, len, mode, pw);

	dprintf(D_ALWAYS, "ZKM: SIGHUP to credmon pid %i\n", get_credmon_pid());
	return SUCCESS;
}

char* getStoredCredential(const char *username, const char *domain)
{
	// TODO: add support for multiple domains

	if ( !username || !domain ) {
		return NULL;
	}

	if (strcmp(username, POOL_PASSWORD_USERNAME) != 0) {
		dprintf(D_ALWAYS,
		        "getStoredCredential: "
		            "only pool password is supported on UNIX\n");
		return NULL;
	} 

	char *filename = param("SEC_PASSWORD_FILE");
	if (filename == NULL) {
		dprintf(D_ALWAYS,
		        "error fetching pool password; "
		            "SEC_PASSWORD_FILE not defined\n");
		return NULL;
	}
<commit_msg>Securely write token, poke credmon, poll for credential cache.  #5287<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2011, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/



#include "condor_common.h"
#include "condor_io.h"
#include "condor_debug.h"
#include "daemon.h"
#include "condor_uid.h"
#include "lsa_mgr.h"
#include "store_cred.h"
#include "condor_config.h"
#include "ipv6_hostname.h"

static int code_store_cred(Stream *socket, char* &user, char* &pw, int &mode);

#ifndef WIN32
	// **** UNIX CODE *****

void SecureZeroMemory(void *p, size_t n)
{
	// TODO: make this Secure
	memset(p, 0, n);
}

// trivial scramble on password file to prevent accidental viewing
// NOTE: its up to the caller to ensure scrambled has enough room
void simple_scramble(char* scrambled,  const char* orig, int len)
{
	const unsigned char deadbeef[] = {0xDE, 0xAD, 0xBE, 0xEF};

	for (int i = 0; i < len; i++) {
		scrambled[i] = orig[i] ^ deadbeef[i % sizeof(deadbeef)];
	}
}

// writes a pool password file using the given password
// returns SUCCESS or FAILURE
//
int write_password_file(const char* path, const char* password)
{
	size_t password_len = strlen(password);
	char scrambled_password[MAX_PASSWORD_LENGTH + 1];
	memset(scrambled_password, 0, MAX_PASSWORD_LENGTH + 1);
	simple_scramble(scrambled_password, password, password_len);
	return secure_write_file(path, scrambled_password, MAX_PASSWORD_LENGTH + 1);
}


// writes data of length len securely to file specified in path
// returns SUCCESS or FAILURE
//
int secure_write_file(const char* path, const char* data, size_t len)
{
		int fd = safe_open_wrapper_follow(path,
		                           O_WRONLY | O_CREAT | O_TRUNC,
		                           0600);
		if (fd == -1) {
			dprintf(D_ALWAYS,
			        "secure_write_file: open failed on %s: %s (%d)\n",
			        path,
			        strerror(errno),
					errno);
			return FAILURE;
		}
		FILE *fp = fdopen(fd, "w");
		if (fp == NULL) {
			dprintf(D_ALWAYS,
			        "secure_write_file: fdopen failed: %s (%d)\n",
			        strerror(errno),
			        errno);
			return FAILURE;
		}
		size_t sz = fwrite(data, 1, len, fp);
		int save_errno = errno;
		fclose(fp);
		if (sz != len) {
			dprintf(D_ALWAYS,
			        "secure_write_file: "
			            "error writing to file: %s (%d)\n",
					strerror(save_errno),
			        save_errno);
			return FAILURE;
		}
		return SUCCESS;
}

int ZKM_UNIX_STORE_CRED(const char *user, const int len, const char *pw, int mode) {
	dprintf(D_ALWAYS, "ZKM: store cred user %s len %i mode %i contents: {%s}\n", user, len, mode, pw);

	char* cred_dir = param("SEC_CREDENTIAL_DIRECTORY");
	if(!cred_dir) {
		dprintf(D_ALWAYS, "ERROR: got STORE_CRED but SEC_CREDENTIAL_DIRECTORY not defined!\n");
		return FAILURE;
	}

	// get username
	char username[256];
	const char *at = strchr(user, '@');
	strncpy(username, user, (at-user));
	username[at-user] = 0;

	// check to see if .cc already exists
	char ccfilename[PATH_MAX];
	sprintf(ccfilename, "%s%c%s.cc", cred_dir, DIR_DELIM_CHAR, username);
	struct stat junk_buf;
	int rc = stat(ccfilename, &junk_buf);
	if (rc==0) {
		// if the credential cache already exists, we don't even need
		// to write the file.  just return success as quickly as
		// possible.
		return SUCCESS;
	}

	// create filenames
	char tmpfilename[PATH_MAX];
	char filename[PATH_MAX];
	sprintf(tmpfilename, "%s%c%s.cred.tmp", cred_dir, DIR_DELIM_CHAR, username);
	sprintf(filename, "%s%c%s.cred", cred_dir, DIR_DELIM_CHAR, username);
	dprintf(D_ALWAYS, "ZKM: writing data to %s\n", tmpfilename);

	// ultimately, decode base64 encode pw
	int pwlen = strlen(pw);

	// write temp file
	priv_state priv = set_root_priv();
	rc = secure_write_file(tmpfilename, pw, pwlen);
	set_priv(priv);

	if (rc != SUCCESS) {
		dprintf(D_ALWAYS, "ZKM: failed to write secure temp file %s\n", tmpfilename);
		return FAILURE;
	}

	// now move into place
	dprintf(D_ALWAYS, "ZKM: renaming %s to %s\n", tmpfilename, filename);

	priv = set_root_priv();
	rc = rename(tmpfilename, filename);
	set_priv(priv);

	if (rc == -1) {
		dprintf(D_ALWAYS, "ZKM: failed to rename %s to %s\n", tmpfilename, filename);

		// should we rm tmpfilename ?
		return FAILURE;
	}

	// now signal the credmon
	pid_t credmon_pid = get_credmon_pid();
	if (credmon_pid == -1) {
		dprintf(D_ALWAYS, "ZKM: failed to get pid of credmon.\n");
		return FAILURE;
	}

	dprintf(D_ALWAYS, "ZKM: sending SIGHUP to credmon pid %i\n", credmon_pid);
	rc = kill(credmon_pid, SIGHUP);
	if (rc == -1) {
		dprintf(D_ALWAYS, "ZKM: failed to signal credmon: %i\n", errno);
		return FAILURE;
	}

	// now poll for existence of .cc file
	int retries = 20;
	while (retries > 0) {
		rc = stat(ccfilename, &junk_buf);
		if (rc==-1) {
			dprintf(D_ALWAYS, "ZKM: errno %i, waiting for %s to appear (%i seconds left)\n", errno, ccfilename, retries);
			sleep(1);
			retries--;
		} else {
			break;
		}
	}
	if (retries == 0) {
		dprintf(D_ALWAYS, "ZKM: FAILURE: credmon never created %s after 20 seconds!\n", ccfilename);
		return FAILURE;
	}

	dprintf(D_ALWAYS, "ZKM: SUCCESS: file %s found after %i seconds\n", ccfilename, 20-retries);
	return SUCCESS;
}

char* getStoredCredential(const char *username, const char *domain)
{
	// TODO: add support for multiple domains

	if ( !username || !domain ) {
		return NULL;
	}

	if (strcmp(username, POOL_PASSWORD_USERNAME) != 0) {
		dprintf(D_ALWAYS,
		        "getStoredCredential: "
		            "only pool password is supported on UNIX\n");
		return NULL;
	} 

	char *filename = param("SEC_PASSWORD_FILE");
	if (filename == NULL) {
		dprintf(D_ALWAYS,
		        "error fetching pool password; "
		            "SEC_PASSWORD_FILE not defined\n");
		return NULL;
	}

{'fraction_non_alphanumeric': 0.14296784192173576, 'fraction_numerical': 0.008523827973653622, 'mean_word_length': 3.5766843971631204, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2340156', 'n_tokens_mistral': 3867, 'n_tokens_neox': 3478, 'n_words': 1075}