/*
 * Attempt to modify an objectSID DSDB_CONTROL_REPLICATED_UPDATE_OID set
 * this should succeed
 */
static void test_modify_of_objectSID_replicated(void **state)
{
	struct ldbtest_ctx *test_ctx =
		talloc_get_type_abort(*state, struct ldbtest_ctx);
	struct ldb_context *ldb 		= test_ctx->ldb;
	struct ldb_message *msg			= ldb_msg_new(test_ctx);
	struct ldb_message_element *el		= NULL;
	struct ldb_request *request		= NULL;
	struct ldb_request *original_request	= NULL;
	int rc;

	msg->dn = ldb_dn_new(msg, ldb, "dc=test");
	add_sid(msg, LOCAL_SID);

	rc = ldb_build_mod_req(
		&request,
		test_ctx->ldb,
		test_ctx,
		msg,
		NULL,
		NULL,
		ldb_op_default_callback,
		NULL);
	assert_int_equal(rc, LDB_SUCCESS);
	assert_non_null(request);
	original_request = request;

	rc = ldb_request_add_control(
		request,
		DSDB_CONTROL_REPLICATED_UPDATE_OID,
		false,
		NULL);
	assert_int_equal(rc, LDB_SUCCESS);

	rc = unique_object_sids_modify(test_ctx->module, request);

	assert_int_equal(rc, LDB_SUCCESS);

	/*
	 * Check that a copy of the request was passed to the next module
	 * and not the original request
	 */
	assert_ptr_not_equal(last_request, original_request);

	/*
	 * Check the flag was set on the request passed to the next
	 * module
	 */
	el = ldb_msg_find_element(last_request->op.add.message, "objectSID");
	assert_non_null(el);
	assert_true(el->flags & LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX);

	/*
	 * Check the flag was not  set on the original request
	 */
	el = ldb_msg_find_element(request->op.add.message, "objectSID");
	assert_non_null(el);
	assert_false(el->flags & LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX);

}
Example #2
0
File: util.c Project: endisd/samba
/*
  add a set of controls to a ldb_request structure based on a set of
  flags. See util.h for a list of available flags
 */
int dsdb_request_add_controls(struct ldb_module *module, struct ldb_request *req, uint32_t dsdb_flags)
{
	int ret;
	if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
		struct ldb_search_options_control *options;
		/* Using the phantom root control allows us to search all partitions */
		options = talloc(req, struct ldb_search_options_control);
		if (options == NULL) {
			ldb_module_oom(module);
			return LDB_ERR_OPERATIONS_ERROR;
		}
		options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
		
		ret = ldb_request_add_control(req,
					      LDB_CONTROL_SEARCH_OPTIONS_OID,
					      true, options);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
		ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
		ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
		struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
		if (!extended_ctrl) {
			ldb_module_oom(module);
			return LDB_ERR_OPERATIONS_ERROR;
		}
		extended_ctrl->type = 1;
		
		ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
		ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	if (dsdb_flags & DSDB_MODIFY_RELAX) {
		ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	return LDB_SUCCESS;
}
Example #3
0
WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
				  TALLOC_CTX *mem_ctx,
				  const struct drsuapi_DsReplicaObjectListItem *first_object,
				  uint32_t *_num,
				  struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
{
	WERROR status;
	const struct dsdb_schema *schema;
	const struct drsuapi_DsReplicaObjectListItem *cur;
	struct ldb_message **objects;
	struct drsuapi_DsReplicaObjectIdentifier2 *ids;
	uint32_t i;
	uint32_t num_objects = 0;
	const char * const attrs[] = {
		"objectGUID",
		"objectSid",
		NULL
	};
	struct ldb_result *res;
	int ret;

	schema = dsdb_get_schema(ldb);
	if (!schema) {
		return WERR_DS_SCHEMA_NOT_LOADED;
	}

	for (cur = first_object; cur; cur = cur->next_object) {
		num_objects++;
	}

	if (num_objects == 0) {
		return WERR_OK;
	}

	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		return WERR_DS_INTERNAL_FAILURE;
	}

	objects	= talloc_array(mem_ctx, struct ldb_message *,
			       num_objects);
	if (objects == NULL) {
		status = WERR_NOMEM;
		goto cancel;
	}

	for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
		status = dsdb_convert_object(ldb, schema,
					     cur, objects, &objects[i]);
		if (!W_ERROR_IS_OK(status)) {
			goto cancel;
		}
	}

	ids = talloc_array(mem_ctx,
			   struct drsuapi_DsReplicaObjectIdentifier2,
			   num_objects);
	if (ids == NULL) {
		status = WERR_NOMEM;
		goto cancel;
	}

	for (i=0; i < num_objects; i++) {
		struct dom_sid *sid = NULL;
		struct ldb_request *add_req;

		DEBUG(6,(__location__ ": adding %s\n", 
			 ldb_dn_get_linearized(objects[i]->dn)));

		ret = ldb_build_add_req(&add_req,
					ldb,
					objects,
					objects[i],
					NULL,
					NULL,
					ldb_op_default_callback,
					NULL);
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}

		ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}
		
		ret = ldb_request(ldb, add_req);
		if (ret == LDB_SUCCESS) {
			ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
		}
		if (ret != LDB_SUCCESS) {
			DEBUG(0,(__location__ ": Failed add of %s - %s\n",
				 ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}

		talloc_free(add_req);

		ret = ldb_search(ldb, objects, &res, objects[i]->dn,
				 LDB_SCOPE_BASE, attrs,
				 "(objectClass=*)");
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}
		ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
		sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
		if (sid) {
			ids[i].sid = *sid;
		} else {
			ZERO_STRUCT(ids[i].sid);
		}
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		return WERR_DS_INTERNAL_FAILURE;
	}

	talloc_free(objects);

	*_num = num_objects;
	*_ids = ids;
	return WERR_OK;

cancel:
	talloc_free(objects);
	ldb_transaction_cancel(ldb);
	return status;
}
Example #4
0
WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
				  TALLOC_CTX *mem_ctx,
				  const struct drsuapi_DsReplicaObjectListItem *first_object,
				  uint32_t *_num,
				  uint32_t dsdb_repl_flags,
				  struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
{
	WERROR status;
	const struct dsdb_schema *schema;
	const struct drsuapi_DsReplicaObjectListItem *cur;
	struct ldb_message **objects;
	struct drsuapi_DsReplicaObjectIdentifier2 *ids;
	uint32_t i;
	uint32_t num_objects = 0;
	const char * const attrs[] = {
		"objectGUID",
		"objectSid",
		NULL
	};
	struct ldb_result *res;
	int ret;

	for (cur = first_object; cur; cur = cur->next_object) {
		num_objects++;
	}

	if (num_objects == 0) {
		return WERR_OK;
	}

	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		return WERR_DS_INTERNAL_FAILURE;
	}

	objects	= talloc_array(mem_ctx, struct ldb_message *,
			       num_objects);
	if (objects == NULL) {
		status = WERR_NOMEM;
		goto cancel;
	}

	schema = dsdb_get_schema(ldb, objects);
	if (!schema) {
		return WERR_DS_SCHEMA_NOT_LOADED;
	}

	for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
		status = dsdb_origin_object_convert(ldb, schema, cur,
						    objects, &objects[i]);
		if (!W_ERROR_IS_OK(status)) {
			goto cancel;
		}
	}

	ids = talloc_array(mem_ctx,
			   struct drsuapi_DsReplicaObjectIdentifier2,
			   num_objects);
	if (ids == NULL) {
		status = WERR_NOMEM;
		goto cancel;
	}

	if (dsdb_repl_flags & DSDB_REPL_FLAG_ADD_NCNAME) {
		/* check for possible NC creation */
		for (i=0; i < num_objects; i++) {
			struct ldb_message *msg = objects[i];
			struct ldb_message_element *el;
			struct ldb_dn *nc_dn;

			if (ldb_msg_check_string_attribute(msg, "objectClass", "crossRef") == 0) {
				continue;
			}
			el = ldb_msg_find_element(msg, "nCName");
			if (el == NULL || el->num_values != 1) {
				continue;
			}
			nc_dn = ldb_dn_from_ldb_val(objects, ldb, &el->values[0]);
			if (!ldb_dn_validate(nc_dn)) {
				continue;
			}
			ret = dsdb_create_partial_replica_NC(ldb, nc_dn);
			if (ret != LDB_SUCCESS) {
				status = WERR_DS_INTERNAL_FAILURE;
				goto cancel;
			}
		}
	}

	for (i=0; i < num_objects; i++) {
		struct dom_sid *sid = NULL;
		struct ldb_request *add_req;

		DEBUG(6,(__location__ ": adding %s\n", 
			 ldb_dn_get_linearized(objects[i]->dn)));

		ret = ldb_build_add_req(&add_req,
					ldb,
					objects,
					objects[i],
					NULL,
					NULL,
					ldb_op_default_callback,
					NULL);
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}

		ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}
		
		ret = ldb_request(ldb, add_req);
		if (ret == LDB_SUCCESS) {
			ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
		}
		if (ret != LDB_SUCCESS) {
			DEBUG(0,(__location__ ": Failed add of %s - %s\n",
				 ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}

		talloc_free(add_req);

		ret = ldb_search(ldb, objects, &res, objects[i]->dn,
				 LDB_SCOPE_BASE, attrs,
				 "(objectClass=*)");
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}
		ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
		sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
		if (sid) {
			ids[i].sid = *sid;
		} else {
			ZERO_STRUCT(ids[i].sid);
		}
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		return WERR_DS_INTERNAL_FAILURE;
	}

	talloc_free(objects);

	*_num = num_objects;
	*_ids = ids;
	return WERR_OK;

cancel:
	talloc_free(objects);
	ldb_transaction_cancel(ldb);
	return status;
}
Example #5
0
static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                                   struct smb_krb5_context *smb_krb5_context,
                                   uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
                                   struct ldb_dn *name_dn, const char *name,
                                   const char *domain_filter, const char *result_filter,
                                   struct drsuapi_DsNameInfo1 *info1)
{
    int ldb_ret;
    struct ldb_result *domain_res = NULL;
    const char * const *domain_attrs;
    const char * const *result_attrs;
    struct ldb_message **result_res = NULL;
    struct ldb_message *result = NULL;
    struct ldb_dn *result_basedn = NULL;
    int i;
    char *p;
    struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);

    const char * const _domain_attrs_1779[] = { "ncName", "dnsRoot", NULL};
    const char * const _result_attrs_null[] = { NULL };

    const char * const _domain_attrs_canonical[] = { "ncName", "dnsRoot", NULL};
    const char * const _result_attrs_canonical[] = { "canonicalName", NULL };

    const char * const _domain_attrs_nt4[] = { "ncName", "dnsRoot", "nETBIOSName", NULL};
    const char * const _result_attrs_nt4[] = { "sAMAccountName", "objectSid", "objectClass", NULL};

    const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL};
    const char * const _result_attrs_guid[] = { "objectGUID", NULL};

    const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", NULL};
    const char * const _result_attrs_display[] = { "displayName", "samAccountName", NULL};

    const char * const _domain_attrs_none[] = { "ncName", "dnsRoot" , NULL};
    const char * const _result_attrs_none[] = { NULL};

    /* here we need to set the attrs lists for domain and result lookups */
    switch (format_desired) {
    case DRSUAPI_DS_NAME_FORMAT_FQDN_1779:
    case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
        domain_attrs = _domain_attrs_1779;
        result_attrs = _result_attrs_null;
        break;
    case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
        domain_attrs = _domain_attrs_canonical;
        result_attrs = _result_attrs_canonical;
        break;
    case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT:
        domain_attrs = _domain_attrs_nt4;
        result_attrs = _result_attrs_nt4;
        break;
    case DRSUAPI_DS_NAME_FORMAT_GUID:
        domain_attrs = _domain_attrs_guid;
        result_attrs = _result_attrs_guid;
        break;
    case DRSUAPI_DS_NAME_FORMAT_DISPLAY:
        domain_attrs = _domain_attrs_display;
        result_attrs = _result_attrs_display;
        break;
    default:
        domain_attrs = _domain_attrs_none;
        result_attrs = _result_attrs_none;
        break;
    }

    if (domain_filter) {
        /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
        ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
                             partitions_basedn,
                             LDB_SCOPE_ONELEVEL,
                             domain_attrs,
                             "%s", domain_filter);

        if (ldb_ret != LDB_SUCCESS) {
            DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s", ldb_errstring(sam_ctx)));
            info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
            return WERR_OK;
        }

        switch (domain_res->count) {
        case 1:
            break;
        case 0:
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        default:
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
            return WERR_OK;
        }

        info1->dns_domain_name	= samdb_result_string(domain_res->msgs[0], "dnsRoot", NULL);
        W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name);
        info1->status		= DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
    } else {
        info1->dns_domain_name	= NULL;
        info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    }

    if (result_filter) {
        int ret;
        struct ldb_result *res;
        if (domain_res) {
            result_basedn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);

            ret = ldb_search(sam_ctx, mem_ctx, &res,
                             result_basedn, LDB_SCOPE_SUBTREE,
                             result_attrs, "%s", result_filter);
            if (ret != LDB_SUCCESS) {
                talloc_free(result_res);
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }
            ldb_ret = res->count;
            result_res = res->msgs;
        } else {
            /* search with the 'phantom root' flag */
            struct ldb_request *req;

            res = talloc_zero(mem_ctx, struct ldb_result);
            W_ERROR_HAVE_NO_MEMORY(res);

            ret = ldb_build_search_req(&req, sam_ctx, mem_ctx,
                                       ldb_get_root_basedn(sam_ctx),
                                       LDB_SCOPE_SUBTREE,
                                       result_filter,
                                       result_attrs,
                                       NULL,
                                       res,
                                       ldb_search_default_callback,
                                       NULL);
            if (ret == LDB_SUCCESS) {
                struct ldb_search_options_control *search_options;
                search_options = talloc(req, struct ldb_search_options_control);
                W_ERROR_HAVE_NO_MEMORY(search_options);
                search_options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;

                ret = ldb_request_add_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID, false, search_options);
            }
            if (ret != LDB_SUCCESS) {
                talloc_free(res);
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }

            ret = ldb_request(sam_ctx, req);

            if (ret == LDB_SUCCESS) {
                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
            }

            talloc_free(req);

            if (ret != LDB_SUCCESS) {
                DEBUG(2, ("DsCrackNameOneFilter phantom root search failed: %s",
                          ldb_errstring(sam_ctx)));
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }
            ldb_ret = res->count;
            result_res = res->msgs;
        }
    } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) {
Example #6
0
bool torture_ldap_sort(struct torture_context *torture)
{
	struct ldb_context *ldb;

	bool ret = false;
	const char *host = torture_setting_string(torture, "host", NULL);
	char *url;
	int i;
	codepoint_t j;
	struct ldb_message_element *elem;
	struct ldb_message *msg;

	struct ldb_server_sort_control **control;
	struct ldb_request *req;
	struct ldb_result *ctx;
	struct ldb_val *prev = NULL;
	const char *prev_txt = NULL;
	int prev_len = 0;
	struct ldb_val *cur = NULL;
	const char *cur_txt = NULL;
	int cur_len = 0;
	struct ldb_dn *dn;
		 
		 
	/* TALLOC_CTX* ctx;*/

	url = talloc_asprintf(torture, "ldap://%s/", host);

	ldb = ldb_wrap_connect(torture, torture->ev, torture->lp_ctx, url,
						 NULL,
						 popt_get_cmdline_credentials(),
						 0);
	torture_assert(torture, ldb, "Failed to make LDB connection to target");

	ctx = talloc_zero(ldb, struct ldb_result);

	control = talloc_array(ctx, struct ldb_server_sort_control *, 2);
	control[0] = talloc(control, struct ldb_server_sort_control);
	control[0]->attributeName = talloc_strdup(control, "cn");
	control[0]->orderingRule = NULL;
	control[0]->reverse = 0;
	control[1] = NULL;

	dn = ldb_get_default_basedn(ldb);
	ldb_dn_add_child_fmt(dn, "cn=users");
	ret = ldb_build_search_req(&req, ldb, ctx,
				   dn,
				   LDB_SCOPE_SUBTREE,
				   "(objectClass=*)", NULL,
				   NULL,
				   ctx, ldb_search_default_callback, NULL);
	torture_assert(torture, ret == LDB_SUCCESS, "Failed to build search request");

	ret = ldb_request_add_control(req, LDB_CONTROL_SERVER_SORT_OID, true, control);
	torture_assert(torture, ret == LDB_SUCCESS, "Failed to add control to search request");

	ret = ldb_request(ldb, req);
	torture_assert(torture, ret == LDB_SUCCESS, ldb_errstring(ldb));

	ret = ldb_wait(req->handle, LDB_WAIT_ALL);
	torture_assert(torture, ret == LDB_SUCCESS, ldb_errstring(ldb));

	ret = true;
	if (ctx->count > 1) {
		for (i=0;i<ctx->count;i++) {
			msg = ctx->msgs[i];
			elem = ldb_msg_find_element(msg,"cn");
			torture_assert_not_null(torture, elem, "msg lacks CN");
			cur = elem->values;
			torture_comment(torture, "cn: %s\n",cur->data);
			if (prev != NULL)
			{
				/* Do only the ascii case right now ... */
				cur_txt = (const char *) cur->data;
				cur_len = cur->length;
				prev_txt = (const char *) prev->data;
				prev_len = prev->length;
				/* Remove leading whitespace as the sort function do so ... */
				while ( cur_txt[0] == cur_txt[1] ) { cur_txt++; cur_len--;}
				while ( prev_txt[0] == prev_txt[1] ) { prev_txt++; prev_len--;}
				while( *(cur_txt) && *(prev_txt) && cur_len && prev_len ) {
					j = toupper_m(*(prev_txt))-toupper_m(*(cur_txt));
					if ( j > 0 ) {
						/* Just check that is not due to trailling white space in prev_txt 
						 * That is to say *cur_txt = 0 and prev_txt = 20 */
						/* Remove trailling whitespace */
						while ( *prev_txt == ' ' ) { prev_txt++; prev_len--;}
						while ( *cur_txt == ' ' ) { cur_txt++; cur_len--;}
						/* Now that potential whitespace are removed if we are at the end 
						 * of the cur_txt then it means that in fact strings were identical
						 */
						torture_assert(torture, *cur_txt && *prev_txt, "Data wrongly sorted");
						break;
					}
					else
					{
						if ( j == 0 )
						{
							if ( *(cur_txt) == ' ') {
								while ( cur_txt[0] == cur_txt[1] ) { cur_txt++; cur_len--;}
								while ( prev_txt[0] == prev_txt[1] ) { prev_txt++; prev_len--;}
							}
							cur_txt++;
							prev_txt++;
							prev_len--;
							cur_len--;
						}
						else
						{
							break;
						} 
					}
				}
				if ( ret != 1 ) {
					break;
				}
			}
			prev = cur; 
		}

	}

	return ret;
}