int proctl_service_wait(void) { const char *myname = "proctl_service_wait"; DWORD timeout = 1000 * 2, ret; char ebuf[256]; HANDLE handle_sem; if (__cur_handle == 0) return (0); /* Create the semaphore, with max value 32K */ handle_sem = CreateSemaphore(NULL, 0, 32 * 1024, NULL); while (1) { ret = WaitForMultipleObjects(__cur_handle, __handles, FALSE, timeout); if (ret == WAIT_OBJECT_0) { proctl_msg_main(); } else if (ret == WAIT_FAILED) { acl_msg_error("%s(%d): wait child object error(%s)", myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); return (-1); } else if (ret != WAIT_TIMEOUT) break; } acl_debug(ACL_DEBUG_PROCTL, 2) ("%s(%d): __cur_handle=%d", myname, __LINE__, __cur_handle); return (0); }
static void proctl_monitor_loop(ACL_VSTREAM *sstream) { const char *myname = "proctl_monitor_loop"; ACL_VSTREAM *client; int n; char buf[1024]; ACL_ARGV *cmd_argv; while (1) { client = acl_vstream_accept(sstream, NULL, 0); if (client == NULL) continue; n = acl_vstream_gets_nonl(client, buf, sizeof(buf)); if (n == ACL_VSTREAM_EOF) continue; acl_debug(ACL_DEBUG_PROCTL, 2) ("%s(%d): get buf(%s)", myname, __LINE__, buf); cmd_argv = acl_argv_split(buf, "|"); if (cmd_argv) proctl_monitor_main(client, cmd_argv->argc, cmd_argv->argv); else usage(client); acl_vstream_close(client); } }
static int check_access_on_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, uint32_t access, struct object_tree *tree) { int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_result *acl_res; struct security_descriptor *sd = NULL; struct dom_sid *sid = NULL; NTSTATUS status; uint32_t access_granted; static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectSid", NULL }; ret = ldb_search(ldb, mem_ctx, &acl_res, dn, LDB_SCOPE_BASE, acl_attrs, NULL); /* we sould be able to find the parent */ if (ret != LDB_SUCCESS) { DEBUG(10,("acl: failed to find object %s\n", ldb_dn_get_linearized(dn))); return ret; } ret = get_sd_from_ldb_message(mem_ctx, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } ret = get_dom_sid_from_ldb_message(mem_ctx, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } status = sec_access_check_ds(sd, acl_user_token(module), access, &access_granted, tree, sid); if (!NT_STATUS_IS_OK(status)) { acl_debug(sd, acl_user_token(module), dn, true, 10); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } return LDB_SUCCESS; }
static int io_close_fn(ACL_ASTREAM *astream, void *context) { const char *myname = "io_close_fn"; CLIENT_ENTRY *entry = (CLIENT_ENTRY *) context; ACL_VSTREAM *stream; stream = acl_aio_vstream(astream); if (stream) acl_debug(22, 2) ("%s: error to stream", myname); else acl_msg_error("not connected"); forward_complete(entry); return (-1); }
int name_mask_delim_opt(const char *context, const NAME_MASK *table, const char *names, const char *delim, int flags) { const char *myname = "name_mask"; char *saved_names = acl_mystrdup(names); char *bp = saved_names; int result = 0; const NAME_MASK *np; char *name; int (*lookup) (const char *, const char *); if (flags & NAME_MASK_ANY_CASE) lookup = strcasecmp; else lookup = strcmp; /* * Break up the names string, and look up each component in the table. If * the name is found, merge its mask with the result. */ while ((name = acl_mystrtok(&bp, delim)) != 0) { for (np = table; /* void */ ; np++) { if (np->name == 0) { if (flags & NAME_MASK_FATAL) acl_msg_fatal("unknown %s value \"%s\" in \"%s\"", context, name, names); if (flags & NAME_MASK_RETURN) { acl_msg_warn("unknown %s value \"%s\" in \"%s\"", context, name, names); return (0); } break; } if (lookup(name, np->name) == 0) { acl_debug(DEBUG_NAME_MASK, 1) ("%s: %s", myname, name); result |= np->mask; break; } } } acl_myfree(saved_names); return (result); }
void acl_proctl_list(const char *progname) { const char *myname = "acl_proctl_list"; char ebuf[256], buf[1024]; ACL_VSTREAM *client; int n; client = proctl_client_open(progname); n = acl_vstream_fprintf(client, "%s|-d|LIST\r\n", progname); if (n == ACL_VSTREAM_EOF) acl_msg_fatal("%s(%d): fprintf to acl_proctl error(%s)", myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); while (1) { if (acl_vstream_gets_nonl(client, buf, sizeof(buf)) == ACL_VSTREAM_EOF) break; acl_debug(ACL_DEBUG_PROCTL, 2) ("%s(%d): buf(%s)", myname, __LINE__, buf); printf("%s\r\n", buf); } proctl_client_close(client); }
static const char *next_server_addr(CLIENT_ENTRY *entry, char *buf, size_t size) { const char *myname = "next_server_addr"; SERVICE *service = entry->service; int i; /* 试着多连一次 */ if (entry->ip_ntry++ > entry->dns_ctx.ip_cnt) { acl_msg_error("%s(%d): domain(%s), ip_ntry(%d) >= ip_cnt(%d)", myname, __LINE__, entry->domain_key, entry->ip_ntry, entry->dns_ctx.ip_cnt); return (NULL); } if (entry->ip_idx == entry->dns_ctx.ip_cnt) entry->ip_idx = 0; for (i = entry->ip_idx; i < entry->dns_ctx.ip_cnt; i++) { if (service->bind_ip_list) { snprintf(buf, size, "%s@%s:%d", service->bind_ip_list[service->bind_ip_index++], entry->dns_ctx.ip[i], entry->dns_ctx.port[i] > 0 ? entry->dns_ctx.port[i] : entry->server_port); if (service->bind_ip_list[service->bind_ip_index] == NULL) service->bind_ip_index = 0; } else { snprintf(buf, size, "%s:%d", entry->dns_ctx.ip[i], entry->dns_ctx.port[i] > 0 ? entry->dns_ctx.port[i] : entry->server_port); } entry->ip_idx++; acl_debug(23, 2) ("%s(%d): domain(%s), addr(%s)", myname, __LINE__, entry->domain_key, buf); return (buf); } return (NULL); }
static int acl_rename(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_dn *oldparent = ldb_dn_get_parent(req, req->op.rename.olddn); struct ldb_dn *newparent = ldb_dn_get_parent(req, req->op.rename.newdn); struct ldb_context *ldb; struct security_descriptor *sd = NULL; struct dom_sid *sid = NULL; struct ldb_result *acl_res; const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; TALLOC_CTX *tmp_ctx = talloc_new(req); NTSTATUS status; uint32_t access_granted; static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectClass", "objectSid", NULL }; DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.rename.olddn)) { return ldb_next_request(module, req); } ldb = ldb_module_get_ctx(module); /* TODO search to include deleted objects */ ret = ldb_search(ldb, req, &acl_res, req->op.rename.olddn, LDB_SCOPE_BASE, acl_attrs, NULL); /* we sould be able to find the parent */ if (ret != LDB_SUCCESS) { DEBUG(10,("acl: failed to find object %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); return ret; } guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; }; guid = attribute_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb), "name"); if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; }; ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } status = sec_access_check_ds(sd, acl_user_token(module), SEC_ADS_WRITE_PROP, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no wp on name\n", ldb_dn_get_linearized(req->op.rename.olddn))); acl_debug(sd, acl_user_token(module), req->op.rename.olddn, true, 10); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } if (ldb_dn_compare(oldparent, newparent) == 0) { /* regular rename, not move, nothing more to do */ return ldb_next_request(module, req); } /* What exactly to do in this case? It would fail anyway.. */ if ((ldb_dn_compare(req->op.rename.newdn, (ldb_get_schema_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.rename.newdn, (ldb_get_config_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.rename.newdn, (ldb_get_root_basedn(ldb))) == 0)) { DEBUG(10,("acl:moving as an NC\n")); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } /* new parent should have create child */ talloc_free(tmp_ctx); tmp_ctx = talloc_new(req); root = NULL; new_node = NULL; guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!guid) { DEBUG(10,("acl:renamed object has no object class\n")); return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_CREATE_CHILD, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; } ret = check_access_on_dn(module, req, newparent, SEC_ADS_CREATE_CHILD, root); if (ret != LDB_SUCCESS) { DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn))); return ret; } /* do we have delete object on the object? */ status = sec_access_check_ds(sd, acl_user_token(module), SEC_STD_DELETE, &access_granted, NULL, sid); if (NT_STATUS_IS_OK(status)) { return ldb_next_request(module, req); } /* what about delete child on the current parent */ ret = check_access_on_dn(module, req, oldparent, SEC_ADS_DELETE_CHILD, NULL); if (ret != LDB_SUCCESS) { DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn))); return ldb_module_done(req, NULL, NULL, ret); } return ldb_next_request(module, req); }
static int acl_modify(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); const struct dsdb_schema *schema = dsdb_get_schema(ldb); int i; bool modify_sd = false; const struct GUID *guid; uint32_t access_granted; struct object_tree *root = NULL; struct object_tree *new_node = NULL; NTSTATUS status; struct ldb_result *acl_res; struct security_descriptor *sd; struct dom_sid *sid = NULL; TALLOC_CTX *tmp_ctx = talloc_new(req); static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectClass", "objectSid", NULL }; /* Don't print this debug statement if elements[0].name is going to be NULL */ if(req->op.mod.message->num_elements > 0) { DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name)); } if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } ret = ldb_search(ldb, req, &acl_res, req->op.mod.message->dn, LDB_SCOPE_BASE, acl_attrs, NULL); if (ret != LDB_SUCCESS) { return ret; } ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { DEBUG(10, ("acl_modify: cannot get descriptor\n")); return ret; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!guid) { DEBUG(10, ("acl_modify: cannot get guid\n")); goto fail; } ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &root, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree\n")); goto fail; } for (i=0; i < req->op.mod.message->num_elements; i++){ const struct dsdb_attribute *attr; /* clearTextPassword is not in schema */ if (strcmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) { attr = dsdb_attribute_by_lDAPDisplayName(schema, "unicodePwd"); } else { attr = dsdb_attribute_by_lDAPDisplayName(schema, req->op.mod.message->elements[i].name); } if (strcmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) { modify_sd = true; } else { if (!attr) { DEBUG(10, ("acl_modify: cannot find attribute %s\n", req->op.mod.message->elements[i].name)); goto fail; } if (!insert_in_object_tree(tmp_ctx, &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree securityGUID\n")); goto fail; } if (!insert_in_object_tree(tmp_ctx, &attr->schemaIDGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree attributeGUID\n")); goto fail; } } } if (root->num_of_children > 0) { status = sec_access_check_ds(sd, acl_user_token(module), SEC_ADS_WRITE_PROP, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no write property access\n", ldb_dn_get_linearized(req->op.mod.message->dn))); acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, 10); talloc_free(tmp_ctx); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } } if (modify_sd) { status = sec_access_check_ds(sd, acl_user_token(module), SEC_STD_WRITE_DAC, &access_granted, NULL, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no write dacl access\n", ldb_dn_get_linearized(req->op.mod.message->dn))); acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, 10); talloc_free(tmp_ctx); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } } talloc_free(tmp_ctx); return ldb_next_request(module, req); fail: talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; }
static int connect_timeout_callback(ACL_ASTREAM *astream, void *context) { const char* myname = "connect_timeout_callback"; CLIENT_ENTRY *entry = (CLIENT_ENTRY *) context; /* 卸载回调函数,防止被重复调用 */ acl_aio_ctl(astream, ACL_AIO_CTL_CONNECT_FN, NULL, ACL_AIO_CTL_CLOSE_HOOK_DEL, connect_close_callback, entry, ACL_AIO_CTL_TIMEO_HOOK_DEL, connect_timeout_callback, entry, ACL_AIO_CTL_END); if (entry->flag_has_replied == 1) return (-1); if (entry->ip_idx < entry->dns_ctx.ip_cnt) { ACL_ASTREAM *server; acl_debug(23, 1) ("%s(%d): begin to connect next ip(%s:%d)", myname, __LINE__, entry->dns_ctx.ip[entry->ip_idx], entry->server_port); /* 断开与服务端的连接,但保持与浏览器端的连接 * XXX: 因为该函数将清除一些关闭回调函数,不知是否会造成某些内存泄漏? * 注,此处并不关闭服务端连接,需要调用者自己来关闭 */ if (client_entry_detach(entry, acl_aio_vstream(entry->server)) == 1) { acl_debug(3, 1) ("%s(%d): entry is freed", myname, __LINE__); return (-1); } server = forward_connect_next(entry); if (server == NULL) goto CONNECT_ERROR; client_entry_set_server(entry, server); acl_aio_ctl(server, ACL_AIO_CTL_CONNECT_FN, connect_callback, ACL_AIO_CTL_CLOSE_HOOK_ADD, connect_close_callback, entry, ACL_AIO_CTL_TIMEO_HOOK_ADD, connect_timeout_callback, entry, ACL_AIO_CTL_CTX, entry, ACL_AIO_CTL_END); /* 通过返回-1,使异步流框架关闭服务端连接 */ return (-1); } CONNECT_ERROR: entry->tm.connect = time(NULL) - entry->tm.stamp; if (entry->ip_idx <= 0) acl_debug(23, 0) ("%s(%d): internal error, ip_idx=0, domain(%s:%d)", myname, __LINE__, entry->domain_key, entry->server_port); else acl_debug(23, 0) ("%s(%d): connect timeout, addr(%s:%d)", myname, __LINE__, entry->dns_ctx.ip[entry->ip_idx - 1], entry->server_port); entry->flag_has_replied = 1; if (entry->connect_timeout_fn) entry->connect_timeout_fn(entry); return (-1); }
int mac_parse(const char *value, MAC_PARSE_FN action, char *context) { const char *myname = "mac_parse"; ACL_VSTRING *buf = acl_vstring_alloc(1); /* result buffer */ const char *vp; /* value pointer */ const char *pp; /* open_paren pointer */ const char *ep; /* string end pointer */ static char open_paren[] = "({"; static char close_paren[] = ")}"; int level; int status = 0; #define SKIP(start, var, cond) \ for (var = start; *var && (cond); var++); acl_debug(DEBUG_MAC, 2) ("%s: %s", myname, value); for (vp = value; *vp;) { if (*vp != '$') { /* ordinary character */ ACL_VSTRING_ADDCH(buf, *vp); vp += 1; } else if (vp[1] == '$') { /* $$ becomes $ */ ACL_VSTRING_ADDCH(buf, *vp); vp += 2; } else { /* found bare $ */ if (ACL_VSTRING_LEN(buf) > 0) MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context); vp += 1; pp = open_paren; if (*vp == *pp || *vp == *++pp) { /* ${x} or $(x) */ level = 1; vp += 1; for (ep = vp; level > 0; ep++) { if (*ep == 0) { acl_msg_warn("truncated macro reference: \"%s\"", value); status |= MAC_PARSE_ERROR; break; } if (*ep == *pp) level++; if (*ep == close_paren[pp - open_paren]) level--; } if (status & MAC_PARSE_ERROR) break; acl_vstring_strncat(buf, vp, level > 0 ? ep - vp : ep - vp - 1); vp = ep; } else { /* plain $x */ SKIP(vp, ep, ACL_ISALNUM(*ep) || *ep == '_'); acl_vstring_strncat(buf, vp, ep - vp); vp = ep; } if (ACL_VSTRING_LEN(buf) == 0) { status |= MAC_PARSE_ERROR; acl_msg_warn("empty macro name: \"%s\"", value); break; } MAC_PARSE_ACTION(status, MAC_PARSE_EXPR, buf, context); } } if (ACL_VSTRING_LEN(buf) > 0 && (status & MAC_PARSE_ERROR) == 0) MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context); /* * Cleanup. */ acl_vstring_free(buf); return (status); }