Exemple #1
0
struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx,
                                      struct tevent_context *ev,
                                      const char *uri,
                                      struct sockaddr_storage *addr,
                                      int addr_len, int timeout)
{
    int ret = EOK;
    struct tevent_req *req;
    struct sss_ldap_init_state *state;

    req = tevent_req_create(mem_ctx, &state, struct sss_ldap_init_state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
        return NULL;
    }

    talloc_set_destructor((TALLOC_CTX *)state, sss_ldap_init_state_destructor);

    state->ldap = NULL;
    state->sd = -1;
    state->uri = uri;

#ifdef HAVE_LDAP_INIT_FD
    struct tevent_req *subreq;

    subreq = sssd_async_socket_init_send(state, ev, addr, addr_len, timeout);
    if (subreq == NULL) {
        ret = ENOMEM;
        DEBUG(SSSDBG_CRIT_FAILURE, "sssd_async_socket_init_send failed.\n");
        goto fail;
    }

    tevent_req_set_callback(subreq, sss_ldap_init_sys_connect_done, req);
    return req;

fail:
    tevent_req_error(req, ret);
#else
    DEBUG(SSSDBG_MINOR_FAILURE, "ldap_init_fd not available, "
              "will use ldap_initialize with uri [%s].\n", uri);
    ret = ldap_initialize(&state->ldap, uri);
    if (ret == LDAP_SUCCESS) {
        tevent_req_done(req);
    } else {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "ldap_initialize failed [%s].\n", sss_ldap_err2string(ret));
        if (ret == LDAP_SERVER_DOWN) {
            tevent_req_error(req, ETIMEDOUT);
        } else {
            tevent_req_error(req, EIO);
        }
    }
#endif

    tevent_req_post(req, ev);
    return req;
}
Exemple #2
0
struct tevent_req *ctdb_conn_init_send(TALLOC_CTX *mem_ctx,
				       struct tevent_context *ev,
				       const char *sock)
{
	struct tevent_req *req, *subreq;
	struct ctdb_conn_init_state *state;

	req = tevent_req_create(mem_ctx, &state, struct ctdb_conn_init_state);
	if (req == NULL) {
		return NULL;
	}

	if (!lp_clustering()) {
		tevent_req_error(req, ENOSYS);
		return tevent_req_post(req, ev);
	}

	if (strlen(sock) >= sizeof(state->addr.sun_path)) {
		tevent_req_error(req, ENAMETOOLONG);
		return tevent_req_post(req, ev);
	}

	state->conn = talloc(state, struct ctdb_conn);
	if (tevent_req_nomem(state->conn, req)) {
		return tevent_req_post(req, ev);
	}

	state->conn->outqueue = tevent_queue_create(
		state->conn, "ctdb outqueue");
	if (tevent_req_nomem(state->conn->outqueue, req)) {
		return tevent_req_post(req, ev);
	}

	state->conn->fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (state->conn->fd == -1) {
		tevent_req_error(req, errno);
		return tevent_req_post(req, ev);
	}
	talloc_set_destructor(state->conn, ctdb_conn_destructor);

	state->addr.sun_family = AF_UNIX;
	strncpy(state->addr.sun_path, sock, sizeof(state->addr.sun_path));

	subreq = async_connect_send(state, ev, state->conn->fd,
				    (struct sockaddr *)&state->addr,
				    sizeof(state->addr), before_connect_cb,
				    after_connect_cb, NULL);
	if (tevent_req_nomem(subreq, req)) {
		return tevent_req_post(req, ev);
	}
	tevent_req_set_callback(subreq, ctdb_conn_init_done, req);
	return req;
}
void setent_notify(struct setent_req_list **list, errno_t err)
{
    struct setent_req_list *reql;

    /* Notify the waiting clients */
    while ((reql = *list) != NULL) {
        /* Each tevent_req_done() call will free
         * the request, removing it from the list.
         */
        if (err == EOK) {
            tevent_req_done(reql->req);
        } else {
            tevent_req_error(reql->req, err);
        }

        if (reql == *list) {
            /* The consumer failed to free the
             * request. Log a bug and continue.
             */
            DEBUG(SSSDBG_FATAL_FAILURE,
                  ("BUG: a callback did not free its request. "
                   "May leak memory\n"));
            /* Skip to the next since a memory leak is non-fatal */
            *list = (*list)->next;
        }
    }
}
Exemple #4
0
static void sdap_sudo_rules_refresh_done(struct tevent_req *subreq)
{
    struct tevent_req *req = NULL;
    struct sdap_sudo_rules_refresh_state *state = NULL;
    char *highest_usn = NULL;
    size_t downloaded_rules_num;
    int ret;

    req = tevent_req_callback_data(subreq, struct tevent_req);
    state = tevent_req_data(req, struct sdap_sudo_rules_refresh_state);

    ret = sdap_sudo_refresh_recv(state, subreq, &state->dp_error, &state->error,
                                 &highest_usn, &downloaded_rules_num);
    talloc_zfree(subreq);
    if (ret != EOK || state->dp_error != DP_ERR_OK || state->error != EOK) {
        goto done;
    }

    /* set highest usn */
    if (highest_usn != NULL) {
        sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn);
    }

    if (downloaded_rules_num != state->num_rules) {
        state->error = ENOENT;
    }

done:
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    tevent_req_done(req);
}
Exemple #5
0
static void sdap_sudo_smart_refresh_done(struct tevent_req *subreq)
{
    struct tevent_req *req = NULL;
    struct sdap_sudo_smart_refresh_state *state = NULL;
    char *highest_usn = NULL;
    int dp_error;
    int error;
    int ret;

    req = tevent_req_callback_data(subreq, struct tevent_req);
    state = tevent_req_data(req, struct sdap_sudo_smart_refresh_state);

    ret = sdap_sudo_refresh_recv(state, subreq, &dp_error, &error,
                                 &highest_usn, NULL);
    if (ret != EOK || dp_error != DP_ERR_OK || error != EOK) {
        goto done;
    }

    DEBUG(SSSDBG_TRACE_FUNC, "Successful smart refresh of sudo rules\n");

    /* set highest usn */
    if (highest_usn != NULL) {
        sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn);
    }

done:
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    tevent_req_done(req);
}
Exemple #6
0
static void tsocket_writev_handler(struct tsocket_context *sock,
                                   void *private_data)
{
    struct tevent_req *req = talloc_get_type(private_data,
                             struct tevent_req);
    struct tsocket_writev_state *state = tevent_req_data(req,
                                         struct tsocket_writev_state);
    int ret;
    int err;
    bool retry;

    ret = tsocket_writev(state->caller.sock,
                         state->iov,
                         state->count);
    err = tsocket_error_from_errno(ret, errno, &retry);
    if (retry) {
        /* retry later */
        return;
    }
    if (tevent_req_error(req, err)) {
        return;
    }

    state->total_written += ret;

    /*
     * we have not written everything yet, so we need to truncate
     * the already written bytes from our iov copy
     */
    while (ret > 0) {
        if (ret < state->iov[0].iov_len) {
            uint8_t *base;
            base = (uint8_t *)state->iov[0].iov_base;
            base += ret;
            state->iov[0].iov_base = base;
            state->iov[0].iov_len -= ret;
            break;
        }
        ret -= state->iov[0].iov_len;
        state->iov += 1;
        state->count -= 1;
    }

    if (state->count > 0) {
        /* more to write */
        return;
    }

    tevent_req_done(req);
}
Exemple #7
0
static void ctdb_conn_init_done(struct tevent_req *subreq)
{
	struct tevent_req *req = tevent_req_callback_data(
		subreq, struct tevent_req);
	int ret, err;

	ret = async_connect_recv(subreq, &err);
	TALLOC_FREE(subreq);
	if (ret == -1) {
		tevent_req_error(req, err);
		return;
	}
	tevent_req_done(req);
}
Exemple #8
0
static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
{
    struct tevent_req *req = tevent_req_callback_data(subreq,
                                                      struct tevent_req);
    struct sss_ldap_init_state *state = tevent_req_data(req,
                                                    struct sss_ldap_init_state);
    int ret;
    int lret;

    ret = sssd_async_socket_init_recv(subreq, &state->sd);
    talloc_zfree(subreq);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "sssd_async_socket_init request failed: [%d]: %s.\n",
              ret, sss_strerror(ret));
        goto fail;
    }
    /* Initialize LDAP handler */

    lret = ldap_init_fd(state->sd, LDAP_PROTO_TCP, state->uri, &state->ldap);
    if (lret != LDAP_SUCCESS) {
        DEBUG(SSSDBG_CRIT_FAILURE,
              "ldap_init_fd failed: %s. [%d][%s]\n",
               sss_ldap_err2string(lret), state->sd, state->uri);
        ret = lret == LDAP_SERVER_DOWN ? ETIMEDOUT : EIO;
        goto fail;
    }

    if (ldap_is_ldaps_url(state->uri)) {
        lret = ldap_install_tls(state->ldap);
        if (lret != LDAP_SUCCESS) {
            if (lret == LDAP_LOCAL_ERROR) {
                DEBUG(SSSDBG_FUNC_DATA, "TLS/SSL already in place.\n");
            } else {
                DEBUG(SSSDBG_CRIT_FAILURE, "ldap_install_tls failed: %s\n",
                          sss_ldap_err2string(lret));
                ret = EIO;
                goto fail;
            }
        }
    }

    tevent_req_done(req);
    return;

fail:
    tevent_req_error(req, ret);
}
Exemple #9
0
static void
sbus_request_notify_error(hash_table_t *table,
                          const char *key,
                          struct tevent_req *req,
                          errno_t error)
{
    struct sbus_request_list *mainreq = NULL;
    struct sbus_request_list *list;
    struct sbus_request_list *item;

    list = sbus_requests_lookup(table, key);
    if (list == NULL) {
        /* This was the only request with no key generator available. */
        tevent_req_error(req, error);
        return;
    }

    /* First notify all chained D-Bus requests. */
    DLIST_FOR_EACH(item, list) {
        /* Remember the main request. */
        if (item->req == req) {
            mainreq = item;
            continue;
        }

        /* We don't want to notify current, invalid or non D-Bus request. */
        if (!item->is_dbus || item->is_invalid) {
            continue;
        }

        sbus_requests_finish(item, error);
    }

    /* Now we finish the main request. */
    sbus_requests_finish(mainreq, error);

    /* And as last, we notify all await requests. */
    DLIST_FOR_EACH(item, list) {
        if (item->is_dbus) {
            continue;
        }

        sbus_requests_finish(item, error);
    }

    sbus_requests_delete(list);
}
Exemple #10
0
static void sdap_sudo_full_refresh_done(struct tevent_req *subreq)
{
    struct tevent_req *req = NULL;
    struct sdap_sudo_full_refresh_state *state = NULL;
    char *highest_usn = NULL;
    int ret;

    req = tevent_req_callback_data(subreq, struct tevent_req);
    state = tevent_req_data(req, struct sdap_sudo_full_refresh_state);

    ret = sdap_sudo_refresh_recv(state, subreq, &state->dp_error,
                                 &state->error, &highest_usn, NULL);
    talloc_zfree(subreq);
    if (ret != EOK || state->dp_error != DP_ERR_OK || state->error != EOK) {
        goto done;
    }

    state->sudo_ctx->full_refresh_done = true;

    /* save the time in the sysdb */
    ret = sysdb_sudo_set_last_full_refresh(state->domain, time(NULL));
    if (ret != EOK) {
        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to save time of "
                                     "a successful full refresh\n");
        /* this is only a minor error that does not affect the functionality,
         * therefore there is no need to report it with tevent_req_error()
         * which would cause problems in the consumers */
    }

    DEBUG(SSSDBG_TRACE_FUNC, "Successful full refresh of sudo rules\n");

    /* set highest usn */
    if (highest_usn != NULL) {
        sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn);
    }

done:
    state->sudo_ctx->full_refresh_in_progress = false;

    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    tevent_req_done(req);
}
Exemple #11
0
static struct tevent_req *aio_posix_pread_send(
	struct vfs_handle_struct *handle,
	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
	struct files_struct *fsp, void *data, size_t n, off_t offset)
{
	struct tevent_req *req;
	struct aio_posix_state *state;
	struct aiocb *a;
	int ret;

	req = tevent_req_create(mem_ctx, &state, struct aio_posix_state);
	if (req == NULL) {
		return NULL;
	}

	a = &state->acb;

	a->aio_fildes = fsp->fh->fd;
	a->aio_buf = data;
	a->aio_nbytes = n;
	a->aio_offset = offset;
	a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
	a->aio_sigevent.sigev_signo  = RT_SIGNAL_AIO;
	a->aio_sigevent.sigev_value.sival_ptr = req;

	ret = aio_read(a);
	if (ret == 0) {
		talloc_set_destructor(state, aio_posix_state_destructor);
		return req;
	}

	if (errno == EAGAIN) {
		/*
		 * aio overloaded, do the sync fallback
		 */
		state->ret = sys_pread(fsp->fh->fd, data, n, offset);
		if (state->ret == -1) {
			state->err = errno;
		}
		tevent_req_done(req);
		return tevent_req_post(req, ev);
	}

	tevent_req_error(req, errno);
	return tevent_req_post(req, ev);
}
Exemple #12
0
/* issue smart refresh of sudo rules */
static struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx,
                                                       struct sdap_sudo_ctx *sudo_ctx)
{
    struct tevent_req *req = NULL;
    struct tevent_req *subreq = NULL;
    struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx;
    struct sdap_attr_map *map = id_ctx->opts->sudorule_map;
    struct sdap_server_opts *srv_opts = id_ctx->srv_opts;
    struct sdap_sudo_smart_refresh_state *state = NULL;
    char *ldap_filter = NULL;
    char *ldap_full_filter = NULL;
    const char *usn;
    int ret;

    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_smart_refresh_state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
        return NULL;
    }

    if (!sudo_ctx->full_refresh_done
            && (srv_opts == NULL || srv_opts->max_sudo_value == 0)) {
        /* Perform full refresh first */
        DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, "
                                  "waiting for full refresh!\n");
        ret = EINVAL;
        goto immediately;
    }

    state->id_ctx = id_ctx;
    state->sysdb = id_ctx->be->domain->sysdb;

    /* Download all rules from LDAP that are newer than usn */
    usn = srv_opts->max_sudo_value;
    if (usn != NULL) {
        ldap_filter = talloc_asprintf(state,
                                      "(&(objectclass=%s)(%s>=%s)(!(%s=%s)))",
                                      map[SDAP_OC_SUDORULE].name,
                                      map[SDAP_AT_SUDO_USN].name, usn,
                                      map[SDAP_AT_SUDO_USN].name, usn);
    } else {
        /* no valid USN value known */
        ldap_filter = talloc_asprintf(state, SDAP_SUDO_FILTER_CLASS,
                                      map[SDAP_OC_SUDORULE].name);
    }
    if (ldap_filter == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    ldap_full_filter = sdap_sudo_get_filter(state, map, sudo_ctx, ldap_filter);
    if (ldap_full_filter == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    /* Do not remove any rules that are already in the sysdb
     * sysdb_filter = NULL; */

    DEBUG(SSSDBG_TRACE_FUNC, "Issuing a smart refresh of sudo rules "
                              "(USN > %s)\n", (usn == NULL ? "0" : usn));

    subreq = sdap_sudo_refresh_send(state, id_ctx->be, id_ctx->opts,
                                    id_ctx->conn->conn_cache,
                                    ldap_full_filter, NULL);
    if (subreq == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    state->subreq = subreq;
    tevent_req_set_callback(subreq, sdap_sudo_smart_refresh_done, req);

    /* free filters */
    talloc_free(ldap_filter);
    talloc_free(ldap_full_filter);

    return req;

immediately:
    if (ret == EOK) {
        tevent_req_done(req);
    } else {
        tevent_req_error(req, ret);
    }
    tevent_req_post(req, id_ctx->be->ev);

    return req;
}
Exemple #13
0
/*
  handle stdout/stderr from the child
 */
static void samba_runcmd_io_handler(struct tevent_context *ev,
				    struct tevent_fd *fde,
				    uint16_t flags,
				    void *private_data)
{
	struct tevent_req *req = talloc_get_type_abort(private_data,
				 struct tevent_req);
	struct samba_runcmd_state *state = tevent_req_data(req,
					   struct samba_runcmd_state);
	int level;
	char *p;
	int n, fd;

	if (!(flags & TEVENT_FD_READ)) {
		return;
	}

	if (fde == state->fde_stdout) {
		level = state->stdout_log_level;
		fd = state->fd_stdout;
	} else if (fde == state->fde_stderr) {
		level = state->stderr_log_level;
		fd = state->fd_stderr;
	} else {
		int status;

		status = tfork_status(&state->tfork, false);
		if (status == -1) {
			if (errno == EAGAIN || errno == EWOULDBLOCK) {
				return;
			}
			DBG_ERR("Bad read on status pipe\n");
			tevent_req_error(req, errno);
			return;
		}
		state->pid = -1;
		TALLOC_FREE(fde);

		if (WIFEXITED(status)) {
			status = WEXITSTATUS(status);
		} else if (WIFSIGNALED(status)) {
			status = WTERMSIG(status);
		} else {
			status = ECHILD;
		}

		DBG_NOTICE("Child %s exited %d\n", state->arg0, status);
		if (status != 0) {
			tevent_req_error(req, status);
			return;
		}

		tevent_req_done(req);
		return;
	}

	n = read(fd, &state->buf[state->buf_used],
		 sizeof(state->buf) - state->buf_used);
	if (n > 0) {
		state->buf_used += n;
	} else if (n == 0) {
		if (fde == state->fde_stdout) {
			talloc_free(fde);
			state->fde_stdout = NULL;
			return;
		}
		if (fde == state->fde_stderr) {
			talloc_free(fde);
			state->fde_stderr = NULL;
			return;
		}
		return;
	}

	while (state->buf_used > 0 &&
	       (p = (char *)memchr(state->buf, '\n', state->buf_used)) != NULL) {
		int n1 = (p - state->buf)+1;
		int n2 = n1 - 1;
		/* swallow \r from child processes */
		if (n2 > 0 && state->buf[n2-1] == '\r') {
			n2--;
		}
		DEBUG(level,("%s: %*.*s\n", state->arg0, n2, n2, state->buf));
		memmove(state->buf, p+1, sizeof(state->buf) - n1);
		state->buf_used -= n1;
	}

	/* the buffer could have completely filled - unfortunately we have
	   no choice but to dump it out straight away */
	if (state->buf_used == sizeof(state->buf)) {
		DEBUG(level,("%s: %*.*s\n",
			     state->arg0, state->buf_used,
			     state->buf_used, state->buf));
		state->buf_used = 0;
	}
}
Exemple #14
0
/*
  run a command as a child process, with a timeout.

  any stdout/stderr from the child will appear in the Samba logs with
  the specified log levels
 */
struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
				     struct tevent_context *ev,
				     struct timeval endtime,
				     int stdout_log_level,
				     int stderr_log_level,
				     const char * const *argv0, ...)
{
	struct tevent_req *req;
	struct samba_runcmd_state *state;
	int p1[2], p2[2], p3[2];
	char **argv;
	va_list ap;

	if (argv0 == NULL) {
		return NULL;
	}

	req = tevent_req_create(mem_ctx, &state,
				struct samba_runcmd_state);
	if (req == NULL) {
		return NULL;
	}

	state->stdout_log_level = stdout_log_level;
	state->stderr_log_level = stderr_log_level;
	state->fd_stdin = -1;

	state->arg0 = talloc_strdup(state, argv0[0]);
	if (tevent_req_nomem(state->arg0, req)) {
		return tevent_req_post(req, ev);
	}

	if (pipe(p1) != 0) {
		tevent_req_error(req, errno);
		return tevent_req_post(req, ev);
	}
	if (pipe(p2) != 0) {
		close(p1[0]);
		close(p1[1]);
		tevent_req_error(req, errno);
		return tevent_req_post(req, ev);
	}
	if (pipe(p3) != 0) {
		close(p1[0]);
		close(p1[1]);
		close(p2[0]);
		close(p2[1]);
		tevent_req_error(req, errno);
		return tevent_req_post(req, ev);
	}

	state->tfork = tfork_create();
	if (state->tfork == NULL) {
		close(p1[0]);
		close(p1[1]);
		close(p2[0]);
		close(p2[1]);
		close(p3[0]);
		close(p3[1]);
		tevent_req_error(req, errno);
		return tevent_req_post(req, ev);
	}
	state->pid = tfork_child_pid(state->tfork);
	if (state->pid != 0) {
		/* the parent */
		close(p1[1]);
		close(p2[1]);
		close(p3[0]);
		state->fd_stdout = p1[0];
		state->fd_stderr = p2[0];
		state->fd_stdin  = p3[1];
		state->fd_status = tfork_event_fd(state->tfork);

		set_blocking(state->fd_stdout, false);
		set_blocking(state->fd_stderr, false);
		set_blocking(state->fd_stdin,  false);
		set_blocking(state->fd_status, false);

		smb_set_close_on_exec(state->fd_stdin);
		smb_set_close_on_exec(state->fd_stdout);
		smb_set_close_on_exec(state->fd_stderr);
		smb_set_close_on_exec(state->fd_status);

		tevent_req_set_cleanup_fn(req, samba_runcmd_cleanup_fn);

		state->fde_stdout = tevent_add_fd(ev, state,
						  state->fd_stdout,
						  TEVENT_FD_READ,
						  samba_runcmd_io_handler,
						  req);
		if (tevent_req_nomem(state->fde_stdout, req)) {
			close(state->fd_stdout);
			close(state->fd_stderr);
			close(state->fd_status);
			return tevent_req_post(req, ev);
		}
		tevent_fd_set_auto_close(state->fde_stdout);

		state->fde_stderr = tevent_add_fd(ev, state,
						  state->fd_stderr,
						  TEVENT_FD_READ,
						  samba_runcmd_io_handler,
						  req);
		if (tevent_req_nomem(state->fde_stdout, req)) {
			close(state->fd_stdout);
			close(state->fd_stderr);
			close(state->fd_status);
			return tevent_req_post(req, ev);
		}
		tevent_fd_set_auto_close(state->fde_stderr);

		state->fde_status = tevent_add_fd(ev, state,
						  state->fd_status,
						  TEVENT_FD_READ,
						  samba_runcmd_io_handler,
						  req);
		if (tevent_req_nomem(state->fde_stdout, req)) {
			close(state->fd_stdout);
			close(state->fd_stderr);
			close(state->fd_status);
			return tevent_req_post(req, ev);
		}
		tevent_fd_set_auto_close(state->fde_status);

		if (!timeval_is_zero(&endtime)) {
			tevent_req_set_endtime(req, ev, endtime);
		}

		return req;
	}

	/* the child */
	close(p1[0]);
	close(p2[0]);
	close(p3[1]);
	close(0);
	close(1);
	close(2);

	/* we want to ensure that all of the network sockets we had
	   open are closed */
	tevent_re_initialise(ev);

	/* setup for logging to go to the parents debug log */
	dup2(p3[0], 0);
	dup2(p1[1], 1);
	dup2(p2[1], 2);

	close(p1[1]);
	close(p2[1]);
	close(p3[0]);

	argv = str_list_copy(state, discard_const_p(const char *, argv0));
	if (!argv) {
		fprintf(stderr, "Out of memory in child\n");
		_exit(255);
	}

	va_start(ap, argv0);
	while (1) {
		const char **l;
		char *arg = va_arg(ap, char *);
		if (arg == NULL) break;
		l = discard_const_p(const char *, argv);
		l = str_list_add(l, arg);
		if (l == NULL) {
			fprintf(stderr, "Out of memory in child\n");
			_exit(255);
		}
		argv = discard_const_p(char *, l);
	}
	va_end(ap);

	(void)execvp(state->arg0, argv);
	fprintf(stderr, "Failed to exec child - %s\n", strerror(errno));
	_exit(255);
	return NULL;
}
Exemple #15
0
/*
  handle stdout/stderr from the child
 */
static void samba_runcmd_io_handler(struct tevent_context *ev,
				    struct tevent_fd *fde,
				    uint16_t flags,
				    void *private_data)
{
	struct tevent_req *req = talloc_get_type_abort(private_data,
				 struct tevent_req);
	struct samba_runcmd_state *state = tevent_req_data(req,
					   struct samba_runcmd_state);
	int level;
	char *p;
	int n, fd;

	if (fde == state->fde_stdout) {
		level = state->stdout_log_level;
		fd = state->fd_stdout;
	} else if (fde == state->fde_stderr) {
		level = state->stderr_log_level;
		fd = state->fd_stderr;
	} else {
		return;
	}

	if (!(flags & TEVENT_FD_READ)) {
		return;
	}

	n = read(fd, &state->buf[state->buf_used],
		 sizeof(state->buf) - state->buf_used);
	if (n > 0) {
		state->buf_used += n;
	} else if (n == 0) {
		if (fde == state->fde_stdout) {
			talloc_free(fde);
			state->fde_stdout = NULL;
		}
		if (fde == state->fde_stderr) {
			talloc_free(fde);
			state->fde_stderr = NULL;
		}
		if (state->fde_stdout == NULL &&
		    state->fde_stderr == NULL) {
			int status;
			/* the child has closed both stdout and
			 * stderr, assume its dead */
			pid_t pid = waitpid(state->pid, &status, 0);
			if (pid != state->pid) {
				if (errno == ECHILD) {
					/* this happens when the
					   parent has set SIGCHLD to
					   SIG_IGN. In that case we
					   can only get error
					   information for the child
					   via its logging. We should
					   stop using SIG_IGN on
					   SIGCHLD in the standard
					   process model.
					*/
					DEBUG(0, ("Error in waitpid() unexpectedly got ECHILD "
						  "for %s child %d - %s, "
						  "someone has set SIGCHLD to SIG_IGN!\n",
					state->arg0, (int)state->pid, strerror(errno)));
					tevent_req_error(req, errno);
					return;
				}
				DEBUG(0,("Error in waitpid() for child %s - %s \n",
					 state->arg0, strerror(errno)));
				if (errno == 0) {
					errno = ECHILD;
				}
				tevent_req_error(req, errno);
				return;
			}
			status = WEXITSTATUS(status);
			DEBUG(3,("Child %s exited with status %d - %s\n",
				 state->arg0, status, strerror(status)));
			if (status != 0) {
				tevent_req_error(req, status);
				return;
			}

			tevent_req_done(req);
			return;
		}
		return;
	}

	while (state->buf_used > 0 &&
	       (p = (char *)memchr(state->buf, '\n', state->buf_used)) != NULL) {
		int n1 = (p - state->buf)+1;
		int n2 = n1 - 1;
		/* swallow \r from child processes */
		if (n2 > 0 && state->buf[n2-1] == '\r') {
			n2--;
		}
		DEBUG(level,("%s: %*.*s\n", state->arg0, n2, n2, state->buf));
		memmove(state->buf, p+1, sizeof(state->buf) - n1);
		state->buf_used -= n1;
	}

	/* the buffer could have completely filled - unfortunately we have
	   no choice but to dump it out straight away */
	if (state->buf_used == sizeof(state->buf)) {
		DEBUG(level,("%s: %*.*s\n",
			     state->arg0, state->buf_used,
			     state->buf_used, state->buf));
		state->buf_used = 0;
	}
}
Exemple #16
0
/* issue full refresh of sudo rules */
static struct tevent_req *sdap_sudo_full_refresh_send(TALLOC_CTX *mem_ctx,
                                                      struct sdap_sudo_ctx *sudo_ctx)
{
    struct tevent_req *req = NULL;
    struct tevent_req *subreq = NULL;
    struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx;
    struct sdap_sudo_full_refresh_state *state = NULL;
    char *ldap_filter = NULL;
    char *ldap_full_filter = NULL;
    char *sysdb_filter = NULL;
    int ret;

    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_full_refresh_state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
        return NULL;
    }

    sudo_ctx->full_refresh_in_progress = true;

    state->sudo_ctx = sudo_ctx;
    state->id_ctx = id_ctx;
    state->sysdb = id_ctx->be->domain->sysdb;
    state->domain = id_ctx->be->domain;

    /* Download all rules from LDAP */
    ldap_filter = talloc_asprintf(state, SDAP_SUDO_FILTER_CLASS,
                                  id_ctx->opts->sudorule_map[SDAP_OC_SUDORULE].name);
    if (ldap_filter == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    ldap_full_filter = sdap_sudo_get_filter(state, id_ctx->opts->sudorule_map,
                                            sudo_ctx, ldap_filter);
    if (ldap_full_filter == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    /* Remove all rules from cache */
    sysdb_filter = talloc_asprintf(state, "(%s=%s)",
                                   SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC);
    if (sysdb_filter == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    DEBUG(SSSDBG_TRACE_FUNC, "Issuing a full refresh of sudo rules\n");

    subreq = sdap_sudo_refresh_send(state, id_ctx->be, id_ctx->opts,
                                    id_ctx->conn->conn_cache,
                                    ldap_full_filter, sysdb_filter);
    if (subreq == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    tevent_req_set_callback(subreq, sdap_sudo_full_refresh_done, req);

    /* free filters */
    talloc_free(ldap_filter);
    talloc_free(ldap_full_filter);
    talloc_free(sysdb_filter);

    return req;

immediately:
    if (ret == EOK) {
        tevent_req_done(req);
    } else {
        tevent_req_error(req, ret);
    }
    tevent_req_post(req, id_ctx->be->ev);

    return req;
}
Exemple #17
0
struct tevent_req *tsocket_writev_send(struct tsocket_context *sock,
                                       TALLOC_CTX *mem_ctx,
                                       const struct iovec *vector,
                                       size_t count)
{
    struct tevent_req *req;
    struct tsocket_writev_state *state;
    int ret;
    int err;
    bool dummy;
    int to_write = 0;
    size_t i;

    req = tevent_req_create(mem_ctx, &state,
                            struct tsocket_writev_state);
    if (!req) {
        return NULL;
    }

    state->caller.sock	= sock;
    state->caller.vector	= vector;
    state->caller.count	= count;

    state->iov		= NULL;
    state->count		= count;
    state->total_written	= 0;

    state->iov = talloc_array(state, struct iovec, count);
    if (tevent_req_nomem(state->iov, req)) {
        goto post;
    }
    memcpy(state->iov, vector, sizeof(struct iovec) * count);

    for (i=0; i < count; i++) {
        int tmp = to_write;

        tmp += state->iov[i].iov_len;

        if (tmp < to_write) {
            tevent_req_error(req, EMSGSIZE);
            goto post;
        }

        to_write = tmp;
    }

    if (to_write == 0) {
        tevent_req_done(req);
        goto post;
    }

    /*
     * this is a fast path, not waiting for the
     * socket to become explicit writeable gains
     * about 10%-20% performance in benchmark tests.
     */
    tsocket_writev_handler(sock, req);
    if (!tevent_req_is_in_progress(req)) {
        goto post;
    }

    talloc_set_destructor(state, tsocket_writev_state_destructor);

    ret = tsocket_set_writeable_handler(sock,
                                        tsocket_writev_handler,
                                        req);
    err = tsocket_error_from_errno(ret, errno, &dummy);
    if (tevent_req_error(req, err)) {
        goto post;
    }

    return req;

post:
    return tevent_req_post(req, sock->event.ctx);
}
Exemple #18
0
/* issue refresh of specific sudo rules */
static struct tevent_req *sdap_sudo_rules_refresh_send(TALLOC_CTX *mem_ctx,
                                                       struct sdap_sudo_ctx *sudo_ctx,
                                                       struct be_ctx *be_ctx,
                                                       struct sdap_options *opts,
                                                       struct sdap_id_conn_cache *conn_cache,
                                                       char **rules)
{
    struct tevent_req *req = NULL;
    struct tevent_req *subreq = NULL;
    struct sdap_sudo_rules_refresh_state *state = NULL;
    TALLOC_CTX *tmp_ctx = NULL;
    char *ldap_filter = NULL;
    char *ldap_full_filter = NULL;
    char *sysdb_filter = NULL;
    char *safe_rule = NULL;
    int ret;
    int i;

    if (rules == NULL) {
        return NULL;
    }

    tmp_ctx = talloc_new(NULL);
    if (tmp_ctx == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
        return NULL;
    }

    req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_rules_refresh_state);
    if (req == NULL) {
        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
        return NULL;
    }

    ldap_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */
    sysdb_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */

    /* Download only selected rules from LDAP */
    /* Remove all selected rules from cache */
    for (i = 0; rules[i] != NULL; i++) {
        ret = sss_filter_sanitize(tmp_ctx, rules[i], &safe_rule);
        if (ret != EOK) {
            ret = ENOMEM;
            goto immediately;
        }

        ldap_filter = talloc_asprintf_append_buffer(ldap_filter, "(%s=%s)",
                                     opts->sudorule_map[SDAP_AT_SUDO_NAME].name,
                                     safe_rule);
        if (ldap_filter == NULL) {
            ret = ENOMEM;
            goto immediately;
        }

        sysdb_filter = talloc_asprintf_append_buffer(sysdb_filter, "(%s=%s)",
                                                     SYSDB_SUDO_CACHE_AT_CN,
                                                     safe_rule);
        if (sysdb_filter == NULL) {
            ret = ENOMEM;
            goto immediately;
        }
    }

    state->id_ctx = sudo_ctx->id_ctx;
    state->num_rules = i;

    ldap_filter = talloc_asprintf(tmp_ctx, "(&"SDAP_SUDO_FILTER_CLASS"(|%s))",
                                  opts->sudorule_map[SDAP_OC_SUDORULE].name,
                                  ldap_filter);
    if (ldap_filter == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    ldap_full_filter = sdap_sudo_get_filter(tmp_ctx, opts->sudorule_map,
                                            sudo_ctx, ldap_filter);
    if (ldap_full_filter == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    sysdb_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|%s))",
                                   SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC,
                                   sysdb_filter);
    if (sysdb_filter == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    subreq = sdap_sudo_refresh_send(req, be_ctx, opts, conn_cache,
                                    ldap_full_filter, sysdb_filter);
    if (subreq == NULL) {
        ret = ENOMEM;
        goto immediately;
    }

    tevent_req_set_callback(subreq, sdap_sudo_rules_refresh_done, req);

    ret = EOK;
immediately:
    talloc_free(tmp_ctx);

    if (ret != EOK) {
        tevent_req_error(req, ret);
        tevent_req_post(req, be_ctx->ev);
    }

    return req;
}
Exemple #19
0
bool tevent_req_nterror(struct tevent_req *req,	NTSTATUS status)
{
	return tevent_req_error(req, NT_STATUS_V(status));
}