summaryrefslogtreecommitdiff
path: root/src/first_run.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/first_run.c')
-rw-r--r--src/first_run.c403
1 files changed, 403 insertions, 0 deletions
diff --git a/src/first_run.c b/src/first_run.c
new file mode 100644
index 0000000..a023306
--- /dev/null
+++ b/src/first_run.c
@@ -0,0 +1,403 @@
+/*
+ * active port forwarder - software for secure forwarding
+ * Copyright (C) 2003-2007 jeremian <jeremian [at] poczta.fm>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <assert.h>
+
+static char* home_dir = NULL;
+static char* home_dir_store = NULL;
+static char* home_dir_key = NULL;
+static char* home_dir_cer = NULL;
+
+typedef struct entry
+{
+ char *key;
+ unsigned char *value;
+} entryT;
+
+static
+entryT entries[6] = {
+ {"countryName", (unsigned char*) "PL"},
+ {"stateOrProvinceName", (unsigned char*) "War-Maz"},
+ {"localityName", (unsigned char*) "Olsztyn"},
+ {"organizationName", (unsigned char*) "gray-world.net"},
+ {"organizationalUnitName", (unsigned char*) "APF team"},
+ {"commonName", (unsigned char*) "Jeremian <jeremian [at] poczta [dot] fm>"},
+};
+
+/*
+ * Function name: callback
+ * Description: Prints the info about rsa key generation events.
+ * Arguments: i, j, k - described in the manual page about RSA_generate_key
+ */
+
+static void
+callback(int i, int j, void* k)
+{
+ if (k == NULL) {
+ printf("%d", i);
+ fflush(stdout);
+ }
+}
+
+/*
+ * Function name: create_apf_dir
+ * Description: Creates .apf directory in ~/ or apf directory locally.
+ * Arguments: type - type of the directory to create:
+ * 0 - .apf in ~/
+ * 1 - apf in current dir
+ * Returns: 0 - success,
+ * 1 - problems with fetching user info,
+ * 2 - home directory is not set,
+ * 3 - calloc failure,
+ * 4 - directory creation failure.
+ */
+
+int
+create_apf_dir(char type)
+{
+ int length;
+ struct stat buf;
+ struct passwd *user = getpwuid(getuid());
+ if (type == 0) {
+ if (user == NULL) {
+ return 1; /* some problems with fetching user info*/
+ }
+ if (user->pw_dir == NULL) {
+ return 2; /* home directory is not set? */
+ }
+ if (home_dir) {
+ free(home_dir);
+ home_dir = NULL;
+ }
+ length = strlen(user->pw_dir);
+ home_dir = calloc(1, length + 6);
+ if (home_dir == NULL) {
+ return 3; /* calloc failed */
+ }
+ strcpy(home_dir, user->pw_dir);
+ if (home_dir[length] == '/') {
+ strcpy(&home_dir[length], ".apf");
+ }
+ else {
+ strcpy(&home_dir[length], "/.apf");
+ }
+ if (stat(home_dir, &buf)) {
+ if (mkdir(home_dir, 0700)) {
+ return 4; /* creating directory failed */
+ }
+ }
+ }
+ else {
+ if (home_dir) {
+ free(home_dir);
+ home_dir = NULL;
+ }
+ home_dir = calloc(1, 4);
+ if (home_dir == NULL) {
+ return 3; /* calloc failed */
+ }
+ strcpy(home_dir, "apf");
+ if (stat(home_dir, &buf)) {
+ if (mkdir(home_dir, 0700)) {
+ return 4; /* creating directory failed */
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Function name: create_publickey_store
+ * Description: Creates the file to store information about public keys.
+ * Arguments: storefile - the pointer to filename
+ * Returns: 0 - success,
+ * >0 - failure.
+ */
+
+int
+create_publickey_store(char** storefile)
+{
+ int store_length, home_length;
+ struct stat buf;
+ FILE* store_file;
+ assert(storefile != NULL);
+ assert((*storefile) != NULL);
+ /* check in local directory first */
+ if (stat(*storefile, &buf) == 0) {
+ return 0;
+ }
+ /* check in home_dir */
+ store_length = strlen(*storefile);
+ home_length = strlen(home_dir);
+ if (home_dir_store) {
+ free(home_dir_store);
+ home_dir_store = NULL;
+ }
+ home_dir_store = calloc(1, home_length + store_length + 2);
+ if (home_dir_store == NULL) {
+ return 1; /* calloc failed */
+ }
+ strcpy(home_dir_store, home_dir);
+ home_dir_store[home_length] = '/';
+ strcpy(&home_dir_store[home_length+1], *storefile);
+ *storefile = home_dir_store;
+ store_file = fopen(home_dir_store, "a");
+ if (store_file == NULL) {
+ return 1;
+ }
+ fclose(store_file);
+ if (stat(home_dir_store, &buf) == 0) {
+ return 0;
+ }
+ return 2;
+}
+
+/*
+ * Function name: generate_rsa_key
+ * Description: Generates the RSA key.
+ * Arguments: keyfile - the pointer to filename
+ * Returns: 0 - success,
+ * >0 - failure.
+ */
+
+int
+generate_rsa_key(char** keyfile)
+{
+ int key_length, home_length;
+ RSA* rsa_key;
+ FILE* rsa_file;
+ struct stat buf;
+ assert(keyfile != NULL);
+ assert((*keyfile) != NULL);
+ /* check in local directory first */
+ if (stat(*keyfile, &buf) == 0) {
+ return 0;
+ }
+ /* check in home_dir */
+ key_length = strlen(*keyfile);
+ home_length = strlen(home_dir);
+ if (home_dir_key) {
+ free(home_dir_key);
+ home_dir_key = NULL;
+ }
+ home_dir_key = calloc(1, home_length + key_length + 2);
+ if (home_dir_key == NULL) {
+ return 1; /* calloc failed */
+ }
+ strcpy(home_dir_key, home_dir);
+ home_dir_key[home_length] = '/';
+ strcpy(&home_dir_key[home_length+1], *keyfile);
+ *keyfile = home_dir_key;
+ if (stat(home_dir_key, &buf) == 0) {
+ return 0;
+ }
+ /* have to generate the key */
+ printf("generating rsa key: 2048 bits\n");
+ rsa_key = RSA_generate_key(2048, 65537, callback, NULL);
+ if (RSA_check_key(rsa_key)==1) {
+ printf(" OK!\n");
+ }
+ else {
+ printf(" FAILED!\n");
+ return 1;
+ }
+
+ rsa_file = fopen(home_dir_key, "a");
+ PEM_write_RSAPrivateKey(rsa_file, rsa_key, NULL, NULL, 0, NULL, NULL);
+ fclose(rsa_file);
+ return 0;
+}
+
+/*
+ * Function name: generate_certificate
+ * Description: Generates X509 certificate.
+ * Arguments: cerfile - the pointer to filename
+ * keyfile - the name of the file with key
+ * Returns: 0 - success,
+ * >0 - failure.
+ */
+
+int
+generate_certificate(char** cerfile, char* keyfile)
+{
+ int cer_length, home_length, i;
+ struct stat buf;
+ X509* cert;
+ X509_REQ* req;
+ X509_NAME* subj;
+ RSA* rsa_key;
+ EVP_PKEY* pkey;
+ const EVP_MD *digest;
+ FILE* fp;
+ assert(cerfile != NULL);
+ assert((*cerfile) != NULL);
+ assert(keyfile != NULL);
+ /* check in local directory first */
+ if (stat(*cerfile, &buf) == 0) {
+ return 0;
+ }
+ /* check in home_dir */
+ cer_length = strlen(*cerfile);
+ home_length = strlen(home_dir);
+ if (home_dir_cer) {
+ free(home_dir_cer);
+ home_dir_cer = NULL;
+ }
+ home_dir_cer = calloc(1, home_length + cer_length + 2);
+ if (home_dir_cer == NULL) {
+ return 1; /* calloc failed */
+ }
+ strcpy(home_dir_cer, home_dir);
+ home_dir_cer[home_length] = '/';
+ strcpy(&home_dir_cer[home_length+1], *cerfile);
+ *cerfile = home_dir_cer;
+ if (stat(home_dir_cer, &buf) == 0) {
+ return 0;
+ }
+ /* have to generate the certificate */
+ printf("generating self signed certificate\n");
+ fp = fopen(keyfile, "r");
+ if (fp == NULL) {
+ return 2; /* can't open keyfile */
+ }
+ rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+ fclose(fp);
+ if (rsa_key == NULL) {
+ return 3; /* can't read RSAPrivateKey */
+ }
+ pkey = EVP_PKEY_new();
+ if (pkey == NULL) {
+ return 4; /* creating new pkey failed */
+ }
+ if (EVP_PKEY_set1_RSA(pkey, rsa_key) == 0) {
+ return 5; /* setting rsa key failed */
+ }
+ req = X509_REQ_new();
+ if (req == NULL) {
+ return 6; /* creating new request failed */
+ }
+ X509_REQ_set_pubkey(req, pkey);
+ subj = X509_NAME_new();
+ if (subj == NULL) {
+ return 7; /* creating new subject name failed */
+ }
+
+ for (i = 0; i < 6; i++)
+ {
+ int nid;
+ X509_NAME_ENTRY *ent;
+
+ if ((nid = OBJ_txt2nid(entries[i].key)) == NID_undef)
+ {
+ return 8; /* finding NID for a key failed */
+ }
+ ent = X509_NAME_ENTRY_create_by_NID(NULL, nid, MBSTRING_ASC,entries[i].value, -1);
+ if (ent == NULL) {
+ return 9; /* creating name entry from NID failed */
+ }
+ if (X509_NAME_add_entry(subj, ent, -1, 0) == 0) {
+ return 10; /* adding entry to name failed */
+ }
+ }
+ if (X509_REQ_set_subject_name(req, subj) == 0) {
+ return 11; /* adding subject to request failed */
+ }
+
+ digest = EVP_sha1();
+
+ if (X509_REQ_sign(req, pkey, digest) == 0) {
+ return 12; /* signing request failed */
+ }
+
+ cert = X509_REQ_to_X509(req, 1000, pkey);
+
+ if (X509_set_version(cert, 2L) == 0) {
+ return 13; /* setting certificate version failed */
+ }
+ ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
+
+ if (cert == NULL) {
+ return 14; /* creating certificate failed */
+ }
+
+ if (X509_sign(cert, pkey, digest) == 0) {
+ return 15; /* signing failed */
+ }
+
+ fp = fopen(home_dir_cer, "w");
+ if (fp == NULL) {
+ return 16; /* writing certificate failed */
+ }
+ PEM_write_X509(fp, cert);
+ fclose(fp);
+
+ EVP_PKEY_free(pkey);
+ X509_REQ_free(req);
+ X509_free(cert);
+ return 0;
+}
+
+/*
+ * Function name: get_store_filename
+ * Description: Returns the name of the file for storing information about public keys.
+ * Returns: The name of the file for storing information about public keys.
+ */
+
+char*
+get_store_filename()
+{
+ return home_dir_store;
+}
+
+/*
+ * Function name: get_key_filename
+ * Description: Returns the name of the file with key.
+ * Returns: The name of the file with key.
+ */
+
+char*
+get_key_filename()
+{
+ return home_dir_key;
+}
+
+/*
+ * Function name: get_cer_filename
+ * Description: Returns the name of the file with certificate.
+ * Returns: The name of the file with certificate.
+ */
+
+char*
+get_cer_filename()
+{
+ return home_dir_cer;
+}