Пример #1
0
const char *silcpurple_session_file(const char *account)
{
	memset(str2, 0, sizeof(str2));
	g_snprintf(str2, sizeof(str2) - 1, "%s" G_DIR_SEPARATOR_S "%s_session",
		   silcpurple_silcdir(), account);
	return (const char *)str2;
}
Пример #2
0
gboolean silcpurple_check_silc_dir(PurpleConnection *gc)
{
	char filename[256], file_public_key[256], file_private_key[256];
	char servfilename[256], clientfilename[256], friendsfilename[256];
	char pkd[256], prd[256];
	struct stat st;
	struct passwd *pw;
	int fd;

	pw = getpwuid(getuid());
	if (!pw) {
		purple_debug_error("silc", "silc: %s\n", g_strerror(errno));
		return FALSE;
	}

	g_snprintf(filename, sizeof(filename) - 1, "%s", silcpurple_silcdir());
	g_snprintf(servfilename, sizeof(servfilename) - 1, "%s" G_DIR_SEPARATOR_S "serverkeys",
		   silcpurple_silcdir());
	g_snprintf(clientfilename, sizeof(clientfilename) - 1, "%s" G_DIR_SEPARATOR_S "clientkeys",
		   silcpurple_silcdir());
	g_snprintf(friendsfilename, sizeof(friendsfilename) - 1, "%s" G_DIR_SEPARATOR_S "friends",
		   silcpurple_silcdir());

	if (pw->pw_uid != geteuid()) {
		purple_debug_error("silc", "Couldn't create directories due to wrong uid!\n");
		return FALSE;
	}

	/*
	 * Check ~/.silc directory
	 */
	if (g_mkdir(filename, 0755) != 0 && errno != EEXIST) {
		purple_debug_error("silc", "Couldn't create '%s' directory\n", filename);
		return FALSE;
	}

#ifndef _WIN32
	if ((g_stat(filename, &st)) == -1) {
		purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n", filename, g_strerror(errno));
		return FALSE;
	} else {
		/* Check the owner of the dir */
		if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
			purple_debug_error("silc", "You don't seem to own '%s' directory\n",
				filename);
			return FALSE;
		}
	}
#endif

	/*
	 * Check ~./silc/serverkeys directory
	 */
	if (g_mkdir(servfilename, 0755) != 0 && errno != EEXIST) {
		purple_debug_error("silc", "Couldn't create '%s' directory\n", servfilename);
		return FALSE;
	}

	/*
	 * Check ~./silc/clientkeys directory
	 */
	if (g_mkdir(clientfilename, 0755) != 0 && errno != EEXIST) {
		purple_debug_error("silc", "Couldn't create '%s' directory\n", clientfilename);
		return FALSE;
	}

	/*
	 * Check ~./silc/friends directory
	 */
	if (g_mkdir(friendsfilename, 0755) != 0 && errno != EEXIST) {
		purple_debug_error("silc", "Couldn't create '%s' directory\n", friendsfilename);
		return FALSE;
	}

	/*
	 * Check Public and Private keys
	 */
	g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
	g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
	g_snprintf(file_public_key, sizeof(file_public_key) - 1, "%s",
		   purple_account_get_string(gc->account, "public-key", pkd));
	g_snprintf(file_private_key, sizeof(file_public_key) - 1, "%s",
		   purple_account_get_string(gc->account, "private-key", prd));

	if ((g_stat(file_public_key, &st)) == -1) {
		/* If file doesn't exist */
		if (errno == ENOENT) {
			purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5);
			if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS,
						  SILCPURPLE_DEF_PKCS_LEN,
						  file_public_key,
						  file_private_key, NULL,
						  (gc->password == NULL)
						  ? "" : gc->password,
						  NULL, NULL, FALSE)) {
				purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
				                             _("Unable to create SILC key pair"));
				return FALSE;
			}

			if ((g_stat(file_public_key, &st)) == -1) {
				purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n",
						   file_public_key, g_strerror(errno));
				return FALSE;
			}
		} else {
			purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n",
					   file_public_key, g_strerror(errno));
			return FALSE;
		}
	}

#ifndef _WIN32
	/* Check the owner of the public key */
	if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
		purple_debug_error("silc", "You don't seem to own your public key!?\n");
		return FALSE;
	}
#endif

	if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) {
		if ((fstat(fd, &st)) == -1) {
			purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
					   file_private_key, g_strerror(errno));
			close(fd);
			return FALSE;
		}
	} else {
		/* If file doesn't exist */
		if (errno == ENOENT) {
			purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5);
			if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS,
						  SILCPURPLE_DEF_PKCS_LEN,
						  file_public_key,
						  file_private_key, NULL,
						  (gc->password == NULL)
						  ? "" : gc->password,
						  NULL, NULL, FALSE)) {
				purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
				                             _("Unable to create SILC key pair"));
				return FALSE;
			}

			if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) {
				if ((fstat(fd, &st)) == -1) {
					purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
							   file_private_key, g_strerror(errno));
					close(fd);
					return FALSE;
				}
			} else {
				purple_debug_error("silc", "Couldn't open '%s' "
					"private key, error: %s\n",
					file_private_key, g_strerror(errno));
				return FALSE;
			}
		} else {
			purple_debug_error("silc", "Couldn't open '%s' private key, error: %s\n",
					   file_private_key, g_strerror(errno));
			return FALSE;
		}
	}

#ifndef _WIN32
	/* Check the owner of the private key */
	if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
		purple_debug_error("silc", "You don't seem to own your private key!?\n");
		if (fd != -1)
			close(fd);
		return FALSE;
	}

	/* Check the permissions for the private key */
	if ((st.st_mode & 0777) != 0600) {
		purple_debug_warning("silc", "Wrong permissions in your private key file `%s'!\n"
			"Trying to change them ...\n", file_private_key);
		if ((fd == -1) || (fchmod(fd, S_IRUSR | S_IWUSR)) == -1) {
			purple_debug_error("silc",
				"Failed to change permissions for private key file!\n"
				"Permissions for your private key file must be 0600.\n");
			if (fd != -1)
				close(fd);
			return FALSE;
		}
		purple_debug_warning("silc", "Done.\n\n");
	}
#endif

	if (fd != -1)
		close(fd);

	return TRUE;
}
Пример #3
0
void silcpurple_verify_public_key(SilcClient client, SilcClientConnection conn,
				  const char *name, SilcConnectionType conn_type,
				  SilcPublicKey public_key,
				  SilcVerifyPublicKey completion, void *context)
{
	PurpleConnection *gc = client->application;
	int i;
	char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
	char *fingerprint, *babbleprint;
	struct passwd *pw;
	struct stat st;
	char *entity = ((conn_type == SILC_CONN_SERVER ||
			 conn_type == SILC_CONN_ROUTER) ?
			"server" : "client");
	PublicKeyVerify verify;
	const char *ip, *hostname;
	SilcUInt16 port;
	unsigned char *pk;
	SilcUInt32 pk_len;

	if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
		purple_notify_error(gc, _("Verify Public Key"),
				    _("Unsupported public key type"), NULL);
		if (completion)
			completion(FALSE, context);
		return;
	}

	pw = getpwuid(getuid());
	if (!pw) {
		if (completion)
			completion(FALSE, context);
		return;
	}

	memset(filename, 0, sizeof(filename));
	memset(filename2, 0, sizeof(filename2));
	memset(file, 0, sizeof(file));

	silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream),
				    NULL, &hostname, &ip, &port);

	pk = silc_pkcs_public_key_encode(public_key, &pk_len);
	if (!pk) {
		if (completion)
			completion(FALSE, context);
		return;
	}

	if (conn_type == SILC_CONN_SERVER ||
	    conn_type == SILC_CONN_ROUTER) {
		if (!name) {
			g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
				   ip, port);
			g_snprintf(filename, sizeof(filename) - 1,
				   "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
				   silcpurple_silcdir(), entity, file);

			g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
				   hostname, port);
			g_snprintf(filename2, sizeof(filename2) - 1,
				   "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
				   silcpurple_silcdir(), entity, file);

			ipf = filename;
			hostf = filename2;
		} else {
			g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
				   name, port);
			g_snprintf(filename, sizeof(filename) - 1,
				   "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
				   silcpurple_silcdir(), entity, file);

			ipf = filename;
		}
	} else {
		/* Replace all whitespaces with `_'. */
		fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
		for (i = 0; i < strlen(fingerprint); i++)
			if (fingerprint[i] == ' ')
				fingerprint[i] = '_';

		g_snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
		g_snprintf(filename, sizeof(filename) - 1,
			   "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s",
			   silcpurple_silcdir(), entity, file);
		silc_free(fingerprint);

		ipf = filename;
	}

	verify = silc_calloc(1, sizeof(*verify));
	if (!verify)
		return;
	verify->client = client;
	verify->conn = conn;
	verify->filename = g_strdup(ipf);
	verify->entity = g_strdup(entity);
	verify->entity_name = (conn_type != SILC_CONN_CLIENT ?
			       (name ? g_strdup(name) : g_strdup(hostname))
			       : NULL);
	verify->public_key = silc_pkcs_public_key_copy(public_key);
	verify->completion = completion;
	verify->context = context;
	fingerprint = verify->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
	babbleprint = verify->babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);

	/* Check whether this key already exists */
	if (g_stat(ipf, &st) < 0 && (!hostf || g_stat(hostf, &st) < 0)) {
		/* Key does not exist, ask user to verify the key and save it */
		silcpurple_verify_ask(name ? name : entity,
				      fingerprint, babbleprint, verify);
		return;
	} else {
		/* The key already exists, verify it. */
		SilcPublicKey public_key;
		unsigned char *encpk;
		SilcUInt32 encpk_len;

		/* Load the key file, try for both IP filename and hostname filename */
		if (!silc_pkcs_load_public_key(ipf, &public_key) &&
		    (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key)))) {
			silcpurple_verify_ask(name ? name : entity,
					    fingerprint, babbleprint, verify);
			return;
		}

		/* Encode the key data */
		encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
		if (!encpk) {
			silcpurple_verify_ask(name ? name : entity,
					    fingerprint, babbleprint, verify);
			return;
		}

		/* Compare the keys */
		if (memcmp(encpk, pk, encpk_len)) {
			/* Ask user to verify the key and save it */
			verify->changed = TRUE;
			silcpurple_verify_ask(name ? name : entity,
					    fingerprint, babbleprint, verify);
			return;
		}

		/* Local copy matched */
		if (completion)
			completion(TRUE, context);
		g_free(verify->filename);
		g_free(verify->entity);
		g_free(verify->entity_name);
		silc_free(verify->fingerprint);
		silc_free(verify->babbleprint);
		silc_pkcs_public_key_free(verify->public_key);
		silc_free(verify);
	}
}
Пример #4
0
static void
silcpurple_add_buddy_save(bool success, void *context)
{
	SilcPurpleBuddyRes r = context;
	PurpleBuddy *b = r->b;
	SilcClient client = r->client;
	SilcClientEntry client_entry;
	SilcAttributePayload attr;
	SilcAttribute attribute;
	SilcVCardStruct vcard;
	SilcAttributeObjMime message, extension;
#ifdef SILC_ATTRIBUTE_USER_ICON
	SilcAttributeObjMime usericon;
#endif
	SilcAttributeObjPk serverpk, usersign, serversign;
	gboolean usign_success = TRUE, ssign_success = TRUE;
	char filename[512], filename2[512], *fingerprint = NULL, *tmp;
	SilcUInt32 len;
	int i;

	if (!success) {
		/* The user did not trust the public key. */
		silcpurple_add_buddy_pk_no(r);
		silc_free(r);
		return;
	}

	if (r->offline) {
		/* User is offline.  Associate the imported public key with
		   this user. */
		fingerprint = silc_hash_fingerprint(NULL, r->offline_pk,
						    r->offline_pk_len);
		for (i = 0; i < strlen(fingerprint); i++)
			if (fingerprint[i] == ' ')
				fingerprint[i] = '_';
		g_snprintf(filename, sizeof(filename) - 1,
			   "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub",
			   silcpurple_silcdir(), fingerprint);
		purple_blist_node_set_string((PurpleBlistNode *)b, "public-key", filename);
		purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL);
		silc_free(fingerprint);
		silc_free(r->offline_pk);
		silc_free(r);
		return;
	}

	/* Get the client entry. */
	client_entry = silc_client_get_client_by_id(r->client, r->conn,
						    &r->client_id);
	if (!client_entry) {
		silc_free(r);
		return;
	}

	memset(&vcard, 0, sizeof(vcard));
	memset(&message, 0, sizeof(message));
	memset(&extension, 0, sizeof(extension));
#ifdef SILC_ATTRIBUTE_USER_ICON
	memset(&usericon, 0, sizeof(usericon));
#endif
	memset(&serverpk, 0, sizeof(serverpk));
	memset(&usersign, 0, sizeof(usersign));
	memset(&serversign, 0, sizeof(serversign));

	/* Now that we have the public key and we trust it now we
	   save the attributes of the buddy and update its status. */

	if (client_entry->attrs) {
		silc_dlist_start(client_entry->attrs);
		while ((attr = silc_dlist_get(client_entry->attrs))
		       != SILC_LIST_END) {
			attribute = silc_attribute_get_attribute(attr);

			switch (attribute) {
			case SILC_ATTRIBUTE_USER_INFO:
				if (!silc_attribute_get_object(attr, (void *)&vcard,
							       sizeof(vcard)))
					continue;
				break;

			case SILC_ATTRIBUTE_STATUS_MESSAGE:
				if (!silc_attribute_get_object(attr, (void *)&message,
							       sizeof(message)))
					continue;
				break;

			case SILC_ATTRIBUTE_EXTENSION:
				if (!silc_attribute_get_object(attr, (void *)&extension,
							       sizeof(extension)))
					continue;
				break;

#ifdef SILC_ATTRIBUTE_USER_ICON
			case SILC_ATTRIBUTE_USER_ICON:
				if (!silc_attribute_get_object(attr, (void *)&usericon,
							       sizeof(usericon)))
					continue;
				break;
#endif

			case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
				if (serverpk.type)
					continue;
				if (!silc_attribute_get_object(attr, (void *)&serverpk,
							       sizeof(serverpk)))
					continue;
				break;

			case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
				if (usersign.data)
					continue;
				if (!silc_attribute_get_object(attr, (void *)&usersign,
							       sizeof(usersign)))
					continue;
				break;

			case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
				if (serversign.data)
					continue;
				if (!silc_attribute_get_object(attr, (void *)&serversign,
							       sizeof(serversign)))
					continue;
				break;

			default:
				break;
			}
		}
	}

	/* Verify the attribute signatures */

	if (usersign.data) {
		SilcPKCS pkcs;
		unsigned char *verifyd;
		SilcUInt32 verify_len;

		silc_pkcs_alloc((unsigned char*)"rsa", &pkcs);
		verifyd = silc_attribute_get_verify_data(client_entry->attrs,
							 FALSE, &verify_len);
		if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){
			if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
							usersign.data,
							usersign.data_len,
							verifyd, verify_len))
				usign_success = FALSE;
		}
		silc_free(verifyd);
	}

	if (serversign.data && purple_strequal(serverpk.type, "silc-rsa")) {
		SilcPublicKey public_key;
		SilcPKCS pkcs;
		unsigned char *verifyd;
		SilcUInt32 verify_len;

		if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len,
						&public_key)) {
			silc_pkcs_alloc((unsigned char *)"rsa", &pkcs);
			verifyd = silc_attribute_get_verify_data(client_entry->attrs,
								 TRUE, &verify_len);
			if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) {
				if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
							       serversign.data,
							       serversign.data_len,
							       verifyd, verify_len))
					ssign_success = FALSE;
			}
			silc_pkcs_public_key_free(public_key);
			silc_free(verifyd);
		}
	}

	fingerprint = silc_fingerprint(client_entry->fingerprint,
				       client_entry->fingerprint_len);
	for (i = 0; i < strlen(fingerprint); i++)
		if (fingerprint[i] == ' ')
			fingerprint[i] = '_';

	if (usign_success || ssign_success) {
		struct passwd *pw;
		struct stat st;

		memset(filename2, 0, sizeof(filename2));

		/* Filename for dir */
		tmp = fingerprint + strlen(fingerprint) - 9;
		g_snprintf(filename, sizeof(filename) - 1,
			   "%s" G_DIR_SEPARATOR_S "friends" G_DIR_SEPARATOR_S "%s",
			   silcpurple_silcdir(), tmp);

		pw = getpwuid(getuid());
		if (!pw)
			return;

		/* Create dir if it doesn't exist */
		if ((g_stat(filename, &st)) == -1) {
			if (errno == ENOENT) {
				if (pw->pw_uid == geteuid()) {
					int ret = g_mkdir(filename, 0755);
					if (ret < 0)
						return;
				}
			}
		}

		/* Save VCard */
		g_snprintf(filename2, sizeof(filename2) - 1,
			   "%s" G_DIR_SEPARATOR_S "vcard", filename);
		if (vcard.full_name) {
			tmp = (char *)silc_vcard_encode(&vcard, &len);
			silc_file_writefile(filename2, tmp, len);
			silc_free(tmp);
		}

		/* Save status message */
		if (message.mime) {
			memset(filename2, 0, sizeof(filename2));
			g_snprintf(filename2, sizeof(filename2) - 1,
				   "%s" G_DIR_SEPARATOR_S "status_message.mime",
				   filename);
			silc_file_writefile(filename2, (char *)message.mime,
					    message.mime_len);
		}

		/* Save extension data */
		if (extension.mime) {
			memset(filename2, 0, sizeof(filename2));
			g_snprintf(filename2, sizeof(filename2) - 1,
				   "%s" G_DIR_SEPARATOR_S "extension.mime",
				   filename);
			silc_file_writefile(filename2, (char *)extension.mime,
					    extension.mime_len);
		}

#ifdef SILC_ATTRIBUTE_USER_ICON
		/* Save user icon */
		if (usericon.mime) {
			SilcMime m = silc_mime_decode(usericon.mime,
						      usericon.mime_len);
			if (m) {
				const char *type = silc_mime_get_field(m, "Content-Type");
				if (purple_strequal(type, "image/jpeg") ||
				    purple_strequal(type, "image/gif") ||
				    purple_strequal(type, "image/bmp") ||
				    purple_strequal(type, "image/png")) {
					const unsigned char *data;
					SilcUInt32 data_len;
					data = silc_mime_get_data(m, &data_len);
					if (data) {
						/* TODO: Check if SILC gives us something to use as the checksum instead */
						purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL);
					}
				}
				silc_mime_free(m);
			}
		}
#endif
	}

	/* Save the public key path to buddy properties, as it is used
	   to identify the buddy in the network (and not the nickname). */
	memset(filename, 0, sizeof(filename));
	g_snprintf(filename, sizeof(filename) - 1,
		   "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub",
		   silcpurple_silcdir(), fingerprint);
	purple_blist_node_set_string((PurpleBlistNode *)b, "public-key", filename);

	/* Update online status */
	purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_AVAILABLE, NULL);

	/* Finally, start watching this user so we receive its status
	   changes from the server */
	g_snprintf(filename2, sizeof(filename2) - 1, "+%s", filename);
	silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey",
				 filename2, NULL);

	silc_free(fingerprint);
	silc_free(r);
}