Index: b/include/asterisk/res_pjsip.h
===================================================================
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -707,6 +707,8 @@ enum ast_sip_endpoint_identifier_type {
 	AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER = (1 << 3),
 	/*! Identify based on request uri */
 	AST_SIP_ENDPOINT_IDENTIFY_BY_REQUEST_URI = (1 << 4),
+	/*! Autocreate identifer */
+	AST_SIP_ENDPOINT_IDENTIFY_BY_AUTOCREATE = (1 << 5),
 };
 AST_VECTOR(ast_sip_identify_by_vector, enum ast_sip_endpoint_identifier_type);
 
@@ -3564,6 +3566,15 @@ char *ast_sip_get_regcontext(void);
 char *ast_sip_get_endpoint_identifier_order(void);
 
 /*!
+ * \brief Retrieve the global autocreate_prefix setting.
+ *
+ * Specifies the prefix for username matching with autocreate endpoint.
+ *
+ * \retval the global autocreate_prefix value
+ */
+char *ast_sip_get_autocreate_prefix(void);
+
+/*!
  * \brief Retrieve the default voicemail extension.
  * \since 13.9.0
  *
@@ -3710,7 +3721,7 @@ struct ast_sip_transport_state *ast_sip_
 
 /*!
  * \brief Return the SIP URI of the Contact header
- * 
+ *
  * \param tdata
  * \retval Pointer to SIP URI of Contact
  * \retval NULL if Contact header not found or not a SIP(S) URI
Index: b/res/res_pjsip/config_global.c
===================================================================
--- a/res/res_pjsip/config_global.c
+++ b/res/res_pjsip/config_global.c
@@ -55,6 +55,7 @@
 #define DEFAULT_TASKPROCESSOR_OVERLOAD_TRIGGER TASKPROCESSOR_OVERLOAD_TRIGGER_GLOBAL
 #define DEFAULT_NOREFERSUB 1
 #define DEFAULT_ALL_CODECS_ON_EMPTY_REINVITE 0
+#define DEFAULT_AUTOCREATE_PREFIX ""
 #define DEFAULT_AUTH_ALGORITHMS_UAS "MD5"
 #define DEFAULT_AUTH_ALGORITHMS_UAC "MD5"
 
@@ -85,6 +86,8 @@ struct global_config {
 		AST_STRING_FIELD(default_voicemail_extension);
 		/*! Realm to use in challenges before an endpoint is identified */
 		AST_STRING_FIELD(default_realm);
+		/*! Autocreate endpoint matching prefix */
+		AST_STRING_FIELD(autocreate_prefix);
 		/*! Default authentication algorithms for UAS */
 		AST_STRING_FIELD(default_auth_algorithms_uas);
 		/*! Default authentication algorithms for UAC */
@@ -324,6 +327,21 @@ char *ast_sip_get_endpoint_identifier_or
 	return res;
 }
 
+char *ast_sip_get_autocreate_prefix(void)
+{
+	char *res;
+	struct global_config *cfg;
+
+	cfg = get_global_cfg();
+	if (!cfg) {
+		return ast_strdup(DEFAULT_AUTOCREATE_PREFIX);
+	}
+
+	res = ast_strdup(cfg->autocreate_prefix);
+	ao2_ref(cfg, -1);
+	return res;
+}
+
 unsigned int ast_sip_get_keep_alive_interval(void)
 {
 	unsigned int interval;
@@ -771,6 +789,9 @@ int ast_sip_initialize_sorcery_global(vo
 		default_voicemail_extension));
 	ast_sorcery_object_field_register(sorcery, "global", "regcontext", DEFAULT_REGCONTEXT,
 		OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, regcontext));
+	ast_sorcery_object_field_register(sorcery, "global", "autocreate_prefix",
+		DEFAULT_AUTOCREATE_PREFIX,
+		OPT_STRINGFIELD_T, 0, STRFLDSET(struct global_config, autocreate_prefix));
 	ast_sorcery_object_field_register(sorcery, "global", "contact_expiration_check_interval",
 		__stringify(DEFAULT_CONTACT_EXPIRATION_CHECK_INTERVAL),
 		OPT_UINT_T, 0, FLDSET(struct global_config, contact_expiration_check_interval));
Index: b/res/res_pjsip_endpoint_identifier_autocreate.c
===================================================================
--- /dev/null
+++ b/res/res_pjsip_endpoint_identifier_autocreate.c
@@ -0,0 +1,214 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+	<depend>pjproject</depend>
+	<depend>res_pjsip</depend>
+	<support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+
+#include "asterisk/res_pjsip.h"
+#include "asterisk/module.h"
+#include "asterisk/sorcery.h"
+
+#define DOMAIN_NAME_LEN 255
+#define USERNAME_LEN    255
+
+static int get_from_header(pjsip_rx_data *rdata, char *username, size_t username_size, char *domain, size_t domain_size)
+{
+	pjsip_uri *from = rdata->msg_info.from->uri;
+	pjsip_sip_uri *sip_from;
+
+	if (!PJSIP_URI_SCHEME_IS_SIP(from) && !PJSIP_URI_SCHEME_IS_SIPS(from)) {
+		return -1;
+	}
+	sip_from = (pjsip_sip_uri *) pjsip_uri_get_uri(from);
+	ast_copy_pj_str(username, &sip_from->user, username_size);
+	ast_copy_pj_str(domain, &sip_from->host, domain_size);
+	return 0;
+}
+
+
+static int create_aor(const char *name) {
+	struct ast_sip_aor *aor;
+	RAII_VAR(void *, template_obj, NULL, ao2_cleanup);
+	RAII_VAR(void *, new_obj, NULL, ao2_cleanup);
+	int ret = -1;
+
+	aor = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", name);
+	if (aor) {
+		ao2_ref(aor, -1);
+		return 0;
+	}
+
+	template_obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", "autocreate");
+	if (!template_obj) {
+		ast_log(LOG_WARNING, "Template aor 'autocreate' not found\n");
+		goto done;
+	}
+
+	new_obj = ast_sorcery_copy_new_id(ast_sip_get_sorcery(), template_obj, name);
+	if (!new_obj) {
+		ast_log(LOG_ERROR, "AOR alloc failed\n");
+		goto done;
+	}
+
+	if (ast_sorcery_create(ast_sip_get_sorcery(), new_obj) == 0) {
+		ret = 1;
+	} else {
+		ast_log(LOG_ERROR, "Failed to create aor\n");
+	}
+
+done:
+	return ret;
+}
+
+static int create_endpoint(const char* template_name, const char *name) {
+	RAII_VAR(void *, template_obj, NULL, ao2_cleanup);
+	RAII_VAR(void *, new_obj, NULL, ao2_cleanup);
+	struct ast_sip_endpoint *endpoint;
+	struct ast_variable *update_set = NULL;
+	struct ast_variable *var;
+	int ret = -1;
+
+	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", name);
+	if (endpoint) {
+		if (endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_AUTOCREATE) {
+			ret = 0;
+		} else {
+			ast_log(LOG_WARNING, "Endpoint '%s' already exists, but is not mine", name);
+		}
+
+		ao2_ref(endpoint, -1);
+		return ret;
+	}
+
+	template_obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", "autocreate");
+	if (!template_obj) {
+		ast_log(LOG_WARNING, "Template endpoint 'autocreate' not found\n");
+		goto done;
+	}
+
+	new_obj = ast_sorcery_copy_new_id(ast_sip_get_sorcery(), template_obj, name);
+	if (!new_obj) {
+		ast_log(LOG_ERROR, "Endpoint alloc failed\n");
+		goto done;
+	}
+
+	var = ast_variable_new("identify_by", "autocreate", "");
+	if (!var) {
+		ast_log(LOG_ERROR, "Cannot create variable\n");
+		goto done;
+	}
+	ast_variable_list_append(&update_set, var);
+
+	var = ast_variable_new("aors", name, "");
+	if (!var) {
+		ast_log(LOG_ERROR, "Cannot create variable\n");
+		goto done;
+	}
+	ast_variable_list_append(&update_set, var);
+
+	if (ast_sorcery_objectset_apply(ast_sip_get_sorcery(), new_obj, update_set)) {
+		ast_log(LOG_ERROR, "Failed to apply enpoint changes\n");
+		goto done;
+	}
+
+	if (ast_sorcery_create(ast_sip_get_sorcery(), new_obj) == 0) {
+		ret = 1;
+	} else {
+		ast_log(LOG_ERROR, "Failed to create endpoint\n");
+	}
+
+done:
+	ast_variables_destroy(update_set);
+	return ret;
+}
+
+static struct ast_sip_endpoint *autocreate_identify(pjsip_rx_data *rdata)
+{
+	struct ast_sip_endpoint *endpoint = NULL;
+	char username[USERNAME_LEN + 1];
+	char domain[DOMAIN_NAME_LEN + 1];
+	char* prefix;
+	int res_aor;
+
+	if (get_from_header(rdata, username, sizeof(username), domain, sizeof(domain))) {
+		return NULL;
+	}
+	AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(username);
+	ast_debug(3, "Attempting identify by From username '%s' domain '%s'\n", username, domain);
+
+	if (!*username) {
+		return NULL;
+	}
+
+	prefix = ast_sip_get_autocreate_prefix();
+	if (!ast_strlen_zero(prefix)) {
+		if (strncmp(username, prefix, strlen(prefix)) != 0) {
+			goto done;
+		}
+	}
+
+	res_aor = create_aor(username);
+	if (res_aor < 0) {
+		goto done;
+	}
+
+	if (create_endpoint("autocreate", username) < 0) {
+		goto done;
+	}
+
+	endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", username);
+
+done:
+	if (endpoint) {
+		ast_debug(3, "Retrieved autocreate endpoint '%s'\n", ast_sorcery_object_get_id(endpoint));
+	}
+
+	ast_free(prefix);
+	return endpoint;
+}
+
+static struct ast_sip_endpoint_identifier autocreate_identifier = {
+	.identify_endpoint = autocreate_identify,
+};
+
+static int load_module(void)
+{
+	ast_sip_register_endpoint_identifier_with_name(&autocreate_identifier, "autocreate");
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+	ast_sip_unregister_endpoint_identifier(&autocreate_identifier);
+	return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "PJSIP Autocreate endpoint identifier",
+	.support_level = AST_MODULE_SUPPORT_CORE,
+	.load = load_module,
+	.unload = unload_module,
+	.requires = "res_pjsip",
+);
Index: b/res/res_pjsip/pjsip_configuration.c
===================================================================
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -426,6 +426,9 @@ static const char *sip_endpoint_identifi
 	case AST_SIP_ENDPOINT_IDENTIFY_BY_REQUEST_URI:
 		str = "request_uri";
 		break;
+	case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTOCREATE:
+		str = "autocreate";
+		break;
 	}
 	return str;
 }
@@ -453,6 +456,8 @@ static int sip_endpoint_identifier_str2t
 		method = AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER;
 	} else if (!strcasecmp(str, "request_uri")) {
 		method = AST_SIP_ENDPOINT_IDENTIFY_BY_REQUEST_URI;
+	} else if (!strcasecmp(str, "autocreate")) {
+		method = AST_SIP_ENDPOINT_IDENTIFY_BY_AUTOCREATE;
 	} else {
 		method = -1;
 	}
Index: b/include/asterisk/sorcery.h
===================================================================
--- a/include/asterisk/sorcery.h
+++ b/include/asterisk/sorcery.h
@@ -1223,6 +1223,18 @@ void *ast_sorcery_lockable_alloc(size_t
 void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id);
 
 /*!
+ * \brief Create a copy of an object with new id
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param object Existing object
+ * \param id ID of the new object
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ */
+void *ast_sorcery_copy_new_id(const struct ast_sorcery *sorcery, const void *object, const char* id);
+
+/*!
  * \brief Create a copy of an object
  *
  * \param sorcery Pointer to a sorcery structure
Index: b/main/sorcery.c
===================================================================
--- a/main/sorcery.c
+++ b/main/sorcery.c
@@ -1839,14 +1839,20 @@ void *ast_sorcery_alloc(const struct ast
 	return details;
 }
 
-void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
+void *ast_sorcery_copy_new_id(const struct ast_sorcery *sorcery, const void *object, const char* id)
 {
 	const struct ast_sorcery_object_details *details = object;
 	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
-	struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->object->type, details->object->id);
+	struct ast_sorcery_object_details *copy;
 	RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
 	int res = 0;
 
+	if (ast_strlen_zero(id)) {
+		return NULL;
+	}
+
+	copy = ast_sorcery_alloc(sorcery, details->object->type, id);
+
 	if (!copy) {
 		return NULL;
 	} else if (object_type->copy) {
@@ -1866,6 +1872,15 @@ void *ast_sorcery_copy(const struct ast_
 	return copy;
 }
 
+
+void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
+{
+	const struct ast_sorcery_object_details *details = object;
+
+	return ast_sorcery_copy_new_id(sorcery, object, details->object->id);
+}
+
+
 int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
 {
 	RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, ast_sorcery_object_get_type(original), OBJ_KEY), ao2_cleanup);
Index: b/res/res_pjsip_registrar.c
===================================================================
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -1188,6 +1188,7 @@ static struct ast_sip_aor *find_registra
 
 		switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) {
 		case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME:
+		case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTOCREATE:
 			uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
 
 			pj_strassign(&username, &uri->user);
Index: b/main/config_options.c
===================================================================
--- a/main/config_options.c
+++ b/main/config_options.c
@@ -1633,7 +1633,6 @@ static int stringfield_handler_fn(const
 	ast_string_field *field = (const char **)(obj + opt->args[0]);
 	struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
 	struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
-
 	if (opt->flags && ast_strlen_zero(var->value)) {
 		return -1;
 	}
Index: b/res/res_pjsip/pjsip_config.xml
===================================================================
--- a/res/res_pjsip/pjsip_config.xml
+++ b/res/res_pjsip/pjsip_config.xml
@@ -3187,6 +3187,9 @@
 					</since>
 					<synopsis>Value used in Max-Forwards header for SIP requests.</synopsis>
 				</configOption>
+				<configOption name="autocreate_prefix" default="">
+					<synopsis>Username prefix to match with autocreate endpoint.</synopsis>
+				</configOption>
 				<configOption name="keep_alive_interval" default="90">
 					<since>
 						<version>13.3.0</version>
