Esempio n. 1
0
/*
  make a IRPC call to the drepl task to ask it to get the RID
  Manager to give us another RID pool.

  This function just sends the message to the drepl task then
  returns immediately. It should be called well before we
  completely run out of RIDs
 */
static void ridalloc_poke_rid_manager(struct ldb_module *module)
{
	struct messaging_context *msg;
	struct server_id *server;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct loadparm_context *lp_ctx =
		(struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
	TALLOC_CTX *tmp_ctx = talloc_new(module);

	msg = messaging_client_init(tmp_ctx, lpcfg_messaging_path(tmp_ctx, lp_ctx),
				    ldb_get_event_context(ldb));
	if (!msg) {
		DEBUG(3,(__location__ ": Failed to create messaging context\n"));
		talloc_free(tmp_ctx);
		return;
	}

	server = irpc_servers_byname(msg, msg, "dreplsrv");
	if (!server) {
		/* this means the drepl service is not running */
		talloc_free(tmp_ctx);
		return;
	}

	messaging_send(msg, server[0], MSG_DREPL_ALLOCATE_RID, NULL);

	/* we don't care if the message got through */
	talloc_free(tmp_ctx);
}
Esempio n. 2
0
/*
  make a IRPC call to the drepl task to ask it to get the RID
  Manager to give us another RID pool.

  This function just sends the message to the drepl task then
  returns immediately. It should be called well before we
  completely run out of RIDs
 */
static int ridalloc_poke_rid_manager(struct ldb_module *module)
{
	struct imessaging_context *msg;
	unsigned num_servers;
	struct server_id *servers;
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct loadparm_context *lp_ctx =
		(struct loadparm_context *)ldb_get_opaque(ldb, "loadparm");
	TALLOC_CTX *tmp_ctx = talloc_new(module);
	NTSTATUS status;

	msg = imessaging_client_init(tmp_ctx, lp_ctx,
				    ldb_get_event_context(ldb));
	if (!msg) {
		ldb_asprintf_errstring(ldb_module_get_ctx(module),
				"Failed to send MSG_DREPL_ALLOCATE_RID, "
				"unable init client messaging context");
		DEBUG(3,(__location__ ": Failed to create messaging context\n"));
		talloc_free(tmp_ctx);
		return LDB_ERR_UNWILLING_TO_PERFORM;
	}

	status = irpc_servers_byname(msg, msg, "dreplsrv",
				     &num_servers, &servers);
	if (!NT_STATUS_IS_OK(status)) {
		ldb_asprintf_errstring(ldb_module_get_ctx(module),
				"Failed to send MSG_DREPL_ALLOCATE_RID, "
				"unable to locate dreplsrv");
		/* this means the drepl service is not running */
		talloc_free(tmp_ctx);
		return LDB_ERR_UNWILLING_TO_PERFORM;
	}

	status = imessaging_send(msg, servers[0], MSG_DREPL_ALLOCATE_RID, NULL);

	/* Only error out if an error happened, not on STATUS_MORE_ENTRIES, ie a delayed message */
	if (NT_STATUS_IS_ERR(status)) {
		struct server_id_buf idbuf;
		ldb_asprintf_errstring(ldb_module_get_ctx(module),
				"Failed to send MSG_DREPL_ALLOCATE_RID to dreplsrv at %s: %s",
				server_id_str_buf(*servers, &idbuf),
				nt_errstr(status));
		talloc_free(tmp_ctx);
		return LDB_ERR_UNWILLING_TO_PERFORM;
	}

	talloc_free(tmp_ctx);
	return LDB_SUCCESS;
}
Esempio n. 3
0
static int ltdb_handle_request(struct ldb_module *module,
			       struct ldb_request *req)
{
	struct ldb_control *control_permissive;
	struct ldb_context *ldb;
	struct tevent_context *ev;
	struct ltdb_context *ac;
	struct tevent_timer *te;
	struct timeval tv;
	unsigned int i;

	ldb = ldb_module_get_ctx(module);

	control_permissive = ldb_request_get_control(req,
					LDB_CONTROL_PERMISSIVE_MODIFY_OID);

	for (i = 0; req->controls && req->controls[i]; i++) {
		if (req->controls[i]->critical &&
		    req->controls[i] != control_permissive) {
			ldb_asprintf_errstring(ldb, "Unsupported critical extension %s",
					       req->controls[i]->oid);
			return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
		}
	}

	if (req->starttime == 0 || req->timeout == 0) {
		ldb_set_errstring(ldb, "Invalid timeout settings");
		return LDB_ERR_TIME_LIMIT_EXCEEDED;
	}

	ev = ldb_get_event_context(ldb);

	ac = talloc_zero(ldb, struct ltdb_context);
	if (ac == NULL) {
		ldb_oom(ldb);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ac->module = module;
	ac->req = req;

	tv.tv_sec = 0;
	tv.tv_usec = 0;
	te = tevent_add_timer(ev, ac, tv, ltdb_callback, ac);
	if (NULL == te) {
		talloc_free(ac);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (req->timeout > 0) {
		tv.tv_sec = req->starttime + req->timeout;
		tv.tv_usec = 0;
		ac->timeout_event = tevent_add_timer(ev, ac, tv,
						     ltdb_timeout, ac);
		if (NULL == ac->timeout_event) {
			talloc_free(ac);
			return LDB_ERR_OPERATIONS_ERROR;
		}
	}

	/* set a spy so that we do not try to use the request context
	 * if it is freed before ltdb_callback fires */
	ac->spy = talloc(req, struct ltdb_req_spy);
	if (NULL == ac->spy) {
		talloc_free(ac);
		return LDB_ERR_OPERATIONS_ERROR;
	}
	ac->spy->ctx = ac;

	talloc_set_destructor((TALLOC_CTX *)ac->spy, ltdb_request_destructor);

	return LDB_SUCCESS;
}
Esempio n. 4
0
static int lldb_handle_request(struct ldb_module *module, struct ldb_request *req)
{
	struct ldb_context *ldb;
	struct lldb_private *lldb;
	struct lldb_context *ac;
	struct tevent_context *ev;
	struct tevent_timer *te;
	struct timeval tv;
	int ret;

	lldb = talloc_get_type(ldb_module_get_private(module), struct lldb_private);
	ldb = ldb_module_get_ctx(module);

	if (req->starttime == 0 || req->timeout == 0) {
		ldb_set_errstring(ldb, "Invalid timeout settings");
		return LDB_ERR_TIME_LIMIT_EXCEEDED;
	}

	ev = ldb_get_event_context(ldb);
	if (NULL == ev) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ac = talloc_zero(ldb, struct lldb_context);
	if (ac == NULL) {
		ldb_set_errstring(ldb, "Out of Memory");
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ac->module = module;
	ac->req = req;
	ac->lldb = lldb;
	ac->msgid = 0;

	if (lldb_dn_is_special(req)) {
		tv.tv_sec = 0;
		tv.tv_usec = 0;
		te = tevent_add_timer(ev, ac, tv,
				     lldb_auto_done_callback, ac);
		if (NULL == te) {
			return LDB_ERR_OPERATIONS_ERROR;
		}

		return LDB_SUCCESS;
	}

	switch (ac->req->operation) {
	case LDB_SEARCH:
		ret = lldb_search(ac);
		break;
	case LDB_ADD:
		ret = lldb_add(ac);
		break;
	case LDB_MODIFY:
		ret = lldb_modify(ac);
		break;
	case LDB_DELETE:
		ret = lldb_delete(ac);
		break;
	case LDB_RENAME:
		ret = lldb_rename(ac);
		break;
	default:
		/* no other op supported */
		ret = LDB_ERR_PROTOCOL_ERROR;
		break;
	}

	if (ret != LDB_SUCCESS) {
		lldb_request_done(ac, NULL, ret);
		return ret;
	}

	tv.tv_sec = 0;
	tv.tv_usec = 0;
	te = tevent_add_timer(ev, ac, tv, lldb_callback, ac);
	if (NULL == te) {
		return LDB_ERR_OPERATIONS_ERROR;
	}


	tv.tv_sec = req->starttime + req->timeout;
	tv.tv_usec = 0;
	te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
	if (NULL == te) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	return LDB_SUCCESS;
}
Esempio n. 5
0
WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                          uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
                          const char *name, struct drsuapi_DsNameInfo1 *info1)
{
    krb5_error_code ret;
    const char *domain_filter = NULL;
    const char *result_filter = NULL;
    struct ldb_dn *name_dn = NULL;

    struct smb_krb5_context *smb_krb5_context = NULL;

    info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    info1->dns_domain_name = NULL;
    info1->result_name = NULL;

    if (!name) {
        return WERR_INVALID_PARAM;
    }

    /* TODO: - fill the correct names in all cases!
     *       - handle format_flags
     */

    /* here we need to set the domain_filter and/or the result_filter */
    switch (format_offered) {
    case DRSUAPI_DS_NAME_FORMAT_UNKNOWN:
    {
        int i;
        enum drsuapi_DsNameFormat formats[] = {
            DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
            DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_CANONICAL,
            DRSUAPI_DS_NAME_FORMAT_GUID, DRSUAPI_DS_NAME_FORMAT_DISPLAY,
            DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
            DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
            DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
        };
        WERROR werr;
        for (i=0; i < ARRAY_SIZE(formats); i++) {
            werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1);
            if (!W_ERROR_IS_OK(werr)) {
                return werr;
            }
            if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
                return werr;
            }
        }
        return werr;
    }

    case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
    case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
    {
        char *str, *s, *account;

        if (strlen(name) == 0) {
            info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
            return WERR_OK;
        }

        str = talloc_strdup(mem_ctx, name);
        W_ERROR_HAVE_NO_MEMORY(str);

        if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) {
            /* Look backwards for the \n, and replace it with / */
            s = strrchr(str, '\n');
            if (!s) {
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }
            s[0] = '/';
        }

        s = strchr(str, '/');
        if (!s) {
            /* there must be at least one / */
            info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
            return WERR_OK;
        }

        s[0] = '\0';
        s++;

        domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(ncName=%s))",
                                        ldb_dn_get_linearized(samdb_dns_domain_to_dn(sam_ctx, mem_ctx, str)));
        W_ERROR_HAVE_NO_MEMORY(domain_filter);

        /* There may not be anything after the domain component (search for the domain itself) */
        if (s[0]) {

            account = strrchr(s, '/');
            if (!account) {
                account = s;
            } else {
                account++;
            }
            account = ldb_binary_encode_string(mem_ctx, account);
            W_ERROR_HAVE_NO_MEMORY(account);
            result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
                                            account);
            W_ERROR_HAVE_NO_MEMORY(result_filter);
        }
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
        char *p;
        char *domain;
        const char *account = NULL;

        domain = talloc_strdup(mem_ctx, name);
        W_ERROR_HAVE_NO_MEMORY(domain);

        p = strchr(domain, '\\');
        if (!p) {
            /* invalid input format */
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        p[0] = '\0';

        if (p[1]) {
            account = &p[1];
        }

        domain_filter = talloc_asprintf(mem_ctx,
                                        "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
                                        ldb_binary_encode_string(mem_ctx, domain));
        W_ERROR_HAVE_NO_MEMORY(domain_filter);
        if (account) {
            result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
                                            ldb_binary_encode_string(mem_ctx, account));
            W_ERROR_HAVE_NO_MEMORY(result_filter);
        }

        talloc_free(domain);
        break;
    }

    /* A LDAP DN as a string */
    case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
        domain_filter = NULL;
        name_dn = ldb_dn_new(mem_ctx, sam_ctx, name);
        if (! ldb_dn_validate(name_dn)) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        break;
    }

    /* A GUID as a string */
    case DRSUAPI_DS_NAME_FORMAT_GUID: {
        struct GUID guid;
        char *ldap_guid;
        NTSTATUS nt_status;
        domain_filter = NULL;

        nt_status = GUID_from_string(name, &guid);
        if (!NT_STATUS_IS_OK(nt_status)) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }

        ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
        if (!ldap_guid) {
            return WERR_NOMEM;
        }
        result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
                                        ldap_guid);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
        domain_filter = NULL;

        result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
                                        ldb_binary_encode_string(mem_ctx, name),
                                        ldb_binary_encode_string(mem_ctx, name));
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }

    /* A S-1234-5678 style string */
    case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
        struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
        char *ldap_sid;

        domain_filter = NULL;
        if (!sid) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx,
                                           sid);
        if (!ldap_sid) {
            return WERR_NOMEM;
        }
        result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
                                        ldap_sid);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
        krb5_principal principal;
        char *unparsed_name;

        ret = smb_krb5_init_context(mem_ctx,
                                    ldb_get_event_context(sam_ctx),
                                    (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
                                    &smb_krb5_context);

        if (ret) {
            return WERR_NOMEM;
        }

        /* Ensure we reject compleate junk first */
        ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
        if (ret) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }

        domain_filter = NULL;

        /* By getting the unparsed name here, we ensure the escaping is correct (and trust the client less) */
        ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_NOMEM;
        }

        krb5_free_principal(smb_krb5_context->krb5_context, principal);

        /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */
        result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))",
                                        ldb_binary_encode_string(mem_ctx, unparsed_name));

        free(unparsed_name);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
        krb5_principal principal;
        char *unparsed_name_short;
        char *service;

        ret = smb_krb5_init_context(mem_ctx,
                                    ldb_get_event_context(sam_ctx),
                                    (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
                                    &smb_krb5_context);

        if (ret) {
            return WERR_NOMEM;
        }

        ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
        if (ret == 0 && principal->name.name_string.len < 2) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_OK;
        }
        ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
                                    KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);

            return dns_domain_from_principal(mem_ctx, smb_krb5_context,
                                             name, info1);
        }

        domain_filter = NULL;

        ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
                                      KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_NOMEM;
        }

        service = principal->name.name_string.val[0];
        if ((principal->name.name_string.len == 2) && (strcasecmp(service, "host") == 0)) {
            /* the 'cn' attribute is just the leading part of the name */
            char *computer_name;
            computer_name = talloc_strndup(mem_ctx, principal->name.name_string.val[1],
                                           strcspn(principal->name.name_string.val[1], "."));
            if (computer_name == NULL) {
                return WERR_NOMEM;
            }

            result_filter = talloc_asprintf(mem_ctx, "(|(&(servicePrincipalName=%s)(objectClass=user))(&(cn=%s)(objectClass=computer)))",
                                            ldb_binary_encode_string(mem_ctx, unparsed_name_short),
                                            ldb_binary_encode_string(mem_ctx, computer_name));
        } else {
            result_filter = talloc_asprintf(mem_ctx, "(&(servicePrincipalName=%s)(objectClass=user))",
                                            ldb_binary_encode_string(mem_ctx, unparsed_name_short));
        }
        krb5_free_principal(smb_krb5_context->krb5_context, principal);
        free(unparsed_name_short);
        W_ERROR_HAVE_NO_MEMORY(result_filter);

        break;
    }
    default: {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    }

    if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
        return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
                                         name_dn, name, info1);
    }

    return DsCrackNameOneFilter(sam_ctx, mem_ctx,
                                smb_krb5_context,
                                format_flags, format_offered, format_desired,
                                name_dn, name,
                                domain_filter, result_filter,
                                info1);
}