int
mm_answer_pty(int socket, Buffer *m)
{
	extern struct monitor *pmonitor;
	Session *s;
	int res, fd0;

	debug3("%s entering", __func__);

	buffer_clear(m);
	s = session_new();
	if (s == NULL)
		goto error;
	s->authctxt = authctxt;
	s->pw = authctxt->pw;
	s->pid = pmonitor->m_pid;
	res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
	if (res == 0)
		goto error;
	fatal_add_cleanup(session_pty_cleanup2, (void *)s);
	pty_setowner(authctxt->pw, s->tty);

	buffer_put_int(m, 1);
	buffer_put_cstring(m, s->tty);
	mm_request_send(socket, MONITOR_ANS_PTY, m);

	mm_send_fd(socket, s->ptyfd);
	mm_send_fd(socket, s->ttyfd);

	/* We need to trick ttyslot */
	if (dup2(s->ttyfd, 0) == -1)
		fatal("%s: dup2", __func__);

	mm_record_login(s, authctxt->pw);

	/* Now we can close the file descriptor again */
	close(0);

	/* make sure nothing uses fd 0 */
	if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0)
		fatal("%s: open(/dev/null): %s", __func__, strerror(errno));
	if (fd0 != 0)
		error("%s: fd0 %d != 0", __func__, fd0);

	/* slave is not needed */
	close(s->ttyfd);
	s->ttyfd = s->ptyfd;
	/* no need to dup() because nobody closes ptyfd */
	s->ptymaster = s->ptyfd;

	debug3("%s: tty %s ptyfd %d",  __func__, s->tty, s->ttyfd);

	return (0);

 error:
	if (s != NULL)
		mm_session_close(s);
	buffer_put_int(m, 0);
	mm_request_send(socket, MONITOR_ANS_PTY, m);
	return (0);
}
Ejemplo n.º 2
0
static gboolean
reload_database (NMSessionMonitor *self, GError **error)
{
	struct stat statbuf;
	char **groups = NULL;
	gsize len = 0, i;
	Session *s;

	free_database (self);

	errno = 0;
	if (stat (CKDB_PATH, &statbuf) != 0) {
		g_set_error (error,
		             NM_SESSION_MONITOR_ERROR,
		             errno == ENOENT ? NM_SESSION_MONITOR_ERROR_NO_DATABASE : NM_SESSION_MONITOR_ERROR_IO_ERROR,
		             "Error statting file " CKDB_PATH ": %s",
		             strerror (errno));
		goto error;
	}
	self->database_mtime = statbuf.st_mtime;

	self->database = g_key_file_new ();
	if (!g_key_file_load_from_file (self->database, CKDB_PATH, G_KEY_FILE_NONE, error))
		goto error;

	groups = g_key_file_get_groups (self->database, &len);
	if (!groups) {
		g_set_error_literal (error,
		                     NM_SESSION_MONITOR_ERROR,
		                     NM_SESSION_MONITOR_ERROR_IO_ERROR,
		                     "Could not load groups from " CKDB_PATH "");
		goto error;
	}

	for (i = 0; i < len; i++) {
		Session *found;

		if (!g_str_has_prefix (groups[i], "Session "))
			continue;

		s = session_new (self->database, groups[i], error);
		if (!s)
			goto error;

		found = g_hash_table_lookup (self->sessions_by_user, (gpointer) s->user);
		if (found) {
			session_merge (s, found);
			session_free (s);
		} else {
			/* Entirely new user */
			g_hash_table_insert (self->sessions_by_user, (gpointer) s->user, s);
			g_hash_table_insert (self->sessions_by_uid, GUINT_TO_POINTER (s->uid), s);
		}
	}

	g_strfreev (groups);
	return TRUE;

error:
	if (groups)
		g_strfreev (groups);
	free_database (self);
	return FALSE;
}
Ejemplo n.º 3
0
		 */
		if (unix_user && conf_path && session->conf_path &&
				strcmp (conf_path, session->conf_path)) {
			nih_free (session->conf_path);
			session->conf_path = NULL;
		}

		if (! session->conf_path)
			session_create_conf_source (session);

		return session;
	}


	/* Didn't find one, make a new one */
	session = NIH_MUST (session_new (parent, unix_process_id ? root : NULL,
					 unix_user));
	session_create_conf_source (session);

	return session;
}

/**
 * session_create_conf_source:
 * @session: Session.
 *
 * Create a new ConfSouce object and associate the specified session
 * with it.
 **/
static void
session_create_conf_source (Session *session)
{
Ejemplo n.º 4
0
/*
 * Create a new peer session in assigned state (connect will start automatically)
 */
static struct stream *peer_session_create(struct peer *peer, struct peer_session *ps)
{
	struct listener *l = LIST_NEXT(&peer->peers->peers_fe->conf.listeners, struct listener *, by_fe);
	struct proxy *p = (struct proxy *)l->frontend; /* attached frontend */
	struct appctx *appctx;
	struct session *sess;
	struct stream *s;
	struct task *t;
	struct connection *conn;

	ps->reconnect = tick_add(now_ms, MS_TO_TICKS(5000));
	ps->statuscode = PEER_SESS_SC_CONNECTCODE;
	s = NULL;

	appctx = appctx_new(&peer_applet);
	if (!appctx)
		goto out_close;

	appctx->st0 = PEER_SESS_ST_CONNECT;
	appctx->ctx.peers.ptr = (void *)ps;

	sess = session_new(p, l, &appctx->obj_type);
	if (!sess) {
		Alert("out of memory in peer_session_create().\n");
		goto out_free_appctx;
	}

	if ((t = task_new()) == NULL) {
		Alert("out of memory in peer_session_create().\n");
		goto out_free_sess;
	}
	t->nice = l->nice;

	if ((s = stream_new(sess, t, &appctx->obj_type)) == NULL) {
		Alert("Failed to initialize stream in peer_session_create().\n");
		goto out_free_task;
	}

	/* The tasks below are normally what is supposed to be done by
	 * fe->accept().
	 */
	s->flags = SF_ASSIGNED|SF_ADDR_SET;

	/* applet is waiting for data */
	si_applet_cant_get(&s->si[0]);
	appctx_wakeup(appctx);

	/* initiate an outgoing connection */
	si_set_state(&s->si[1], SI_ST_ASS);

	/* automatically prepare the stream interface to connect to the
	 * pre-initialized connection in si->conn.
	 */
	if (unlikely((conn = conn_new()) == NULL))
		goto out_free_strm;

	conn_prepare(conn, peer->proto, peer->xprt);
	si_attach_conn(&s->si[1], conn);

	conn->target = s->target = &s->be->obj_type;
	memcpy(&conn->addr.to, &peer->addr, sizeof(conn->addr.to));
	s->do_log = NULL;
	s->uniq_id = 0;

	s->res.flags |= CF_READ_DONTWAIT;

	l->nbconn++; /* warning! right now, it's up to the handler to decrease this */
	p->feconn++;/* beconn will be increased later */
	jobs++;
	if (!(s->sess->listener->options & LI_O_UNLIMITED))
		actconn++;
	totalconn++;

	ps->appctx = appctx;
	ps->stream = s;
	return s;

	/* Error unrolling */
 out_free_strm:
	LIST_DEL(&s->list);
	pool_free2(pool2_stream, s);
 out_free_task:
	task_free(t);
 out_free_sess:
	session_free(sess);
 out_free_appctx:
	appctx_free(appctx);
 out_close:
	return s;
}
Ejemplo n.º 5
0
enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq)
{
	struct args		*args = self->args;
	struct session		*s;
	struct winlink		*wl;
	struct client		*c;
	const char		*cmd, *template;
	char			*cause, *cp;
	int			 idx, last, detached, cwd, fd = -1;
	struct format_tree	*ft;

	if (args_has(args, 'a')) {
		wl = cmd_find_window(cmdq, args_get(args, 't'), &s);
		if (wl == NULL)
			return (CMD_RETURN_ERROR);
		idx = wl->idx + 1;

		/* Find the next free index. */
		for (last = idx; last < INT_MAX; last++) {
			if (winlink_find_by_index(&s->windows, last) == NULL)
				break;
		}
		if (last == INT_MAX) {
			cmdq_error(cmdq, "no free window indexes");
			return (CMD_RETURN_ERROR);
		}

		/* Move everything from last - 1 to idx up a bit. */
		for (; last > idx; last--) {
			wl = winlink_find_by_index(&s->windows, last - 1);
			server_link_window(s, wl, s, last, 0, 0, NULL);
			server_unlink_window(s, wl);
		}
	} else {
		if ((idx = cmd_find_index(cmdq, args_get(args, 't'), &s)) == -2)
			return (CMD_RETURN_ERROR);
	}
	detached = args_has(args, 'd');

	if (args->argc == 0)
		cmd = options_get_string(&s->options, "default-command");
	else
		cmd = args->argv[0];

	if (args_has(args, 'c')) {
		ft = format_create();
		if ((c = cmd_find_client(cmdq, NULL, 1)) != NULL)
			format_client(ft, c);
		format_session(ft, s);
		format_winlink(ft, s, s->curw);
		format_window_pane(ft, s->curw->window->active);
		cp = format_expand(ft, args_get(args, 'c'));
		format_free(ft);

		if (cp != NULL && *cp != '\0') {
			fd = open(cp, O_RDONLY|O_DIRECTORY);
			free(cp);
			if (fd == -1) {
				cmdq_error(cmdq, "bad working directory: %s",
				    strerror(errno));
				return (CMD_RETURN_ERROR);
			}
		} else if (cp != NULL)
			free(cp);
		cwd = fd;
	} else if (cmdq->client != NULL && cmdq->client->session == NULL)
		cwd = cmdq->client->cwd;
	else
		cwd = s->cwd;

	wl = NULL;
	if (idx != -1)
		wl = winlink_find_by_index(&s->windows, idx);
	if (wl != NULL && args_has(args, 'k')) {
		/*
		 * Can't use session_detach as it will destroy session if this
		 * makes it empty.
		 */
		notify_window_unlinked(s, wl->window);
		wl->flags &= ~WINLINK_ALERTFLAGS;
		winlink_stack_remove(&s->lastw, wl);
		winlink_remove(&s->windows, wl);

		/* Force select/redraw if current. */
		if (wl == s->curw) {
			detached = 0;
			s->curw = NULL;
		}
	}

	if (idx == -1)
		idx = -1 - options_get_number(&s->options, "base-index");
	wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause);
	if (wl == NULL) {
		cmdq_error(cmdq, "create window failed: %s", cause);
		free(cause);
		goto error;
	}
	if (!detached) {
		session_select(s, wl->idx);
		server_redraw_session_group(s);
	} else
		server_status_session_group(s);

	if (args_has(args, 'P')) {
		if ((template = args_get(args, 'F')) == NULL)
Ejemplo n.º 6
0
int
cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
	struct cmd_new_window_data	*data = self->data;
	struct session			*s;
	struct winlink			*wl;
	char				*cmd, *cwd, *cause;
	int				 idx, last;

	if (data == NULL)
		return (0);

	if (data->flag_insert_after) {
		if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
			return (-1);
		idx = wl->idx + 1;

		/* Find the next free index. */
		for (last = idx; last < INT_MAX; last++) {
			if (winlink_find_by_index(&s->windows, last) == NULL)
				break;
		}
		if (last == INT_MAX) {
			ctx->error(ctx, "no free window indexes");
			return (-1);
		}

		/* Move everything from last - 1 to idx up a bit. */
		for (; last > idx; last--) {
			wl = winlink_find_by_index(&s->windows, last - 1);
			server_link_window(s, wl, s, last, 0, 0, NULL);
			server_unlink_window(s, wl);
		}
	} else {
		if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
			return (-1);
	}

	wl = NULL;
	if (idx != -1)
		wl = winlink_find_by_index(&s->windows, idx);
	if (wl != NULL && data->flag_kill) {
		/*
		 * Can't use session_detach as it will destroy session if this
		 * makes it empty.
		 */
		wl->flags &= ~WINLINK_ALERTFLAGS;
		winlink_stack_remove(&s->lastw, wl);
		winlink_remove(&s->windows, wl);

		/* Force select/redraw if current. */
		if (wl == s->curw) {
			data->flag_detached = 0;
			s->curw = NULL;
		}
	}

	cmd = data->cmd;
	if (cmd == NULL)
		cmd = options_get_string(&s->options, "default-command");
	cwd = options_get_string(&s->options, "default-path");
	if (*cwd == '\0') {
		if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
			cwd = ctx->cmdclient->cwd;
		else
			cwd = s->cwd;
	}

	if (idx == -1)
		idx = -1 - options_get_number(&s->options, "base-index");
	wl = session_new(s, data->name, cmd, cwd, idx, &cause);
	if (wl == NULL) {
		ctx->error(ctx, "create window failed: %s", cause);
		xfree(cause);
		return (-1);
	}
	if (!data->flag_detached) {
		session_select(s, wl->idx);
		server_redraw_session_group(s);
	} else
		server_status_session_group(s);

	if (data->flag_print)
		ctx->print(ctx, "%s:%u", s->name, wl->idx);
	return (0);
}
Ejemplo n.º 7
0
int
cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
{
	struct args	*args = self->args;
	struct session	*s;
	struct winlink	*wl;
	struct client	*c;
	const char	*cmd, *cwd;
	char		*cause;
	int		 idx, last, detached;

	if (args_has(args, 'a')) {
		wl = cmd_find_window(ctx, args_get(args, 't'), &s);
		if (wl == NULL)
			return (-1);
		idx = wl->idx + 1;

		/* Find the next free index. */
		for (last = idx; last < INT_MAX; last++) {
			if (winlink_find_by_index(&s->windows, last) == NULL)
				break;
		}
		if (last == INT_MAX) {
			ctx->error(ctx, "no free window indexes");
			return (-1);
		}

		/* Move everything from last - 1 to idx up a bit. */
		for (; last > idx; last--) {
			wl = winlink_find_by_index(&s->windows, last - 1);
			server_link_window(s, wl, s, last, 0, 0, NULL);
			server_unlink_window(s, wl);
		}
	} else {
		if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2)
			return (-1);
	}
	detached = args_has(args, 'd');

	wl = NULL;
	if (idx != -1)
		wl = winlink_find_by_index(&s->windows, idx);
	if (wl != NULL && args_has(args, 'k')) {
		/*
		 * Can't use session_detach as it will destroy session if this
		 * makes it empty.
		 */
		control_notify_window_removed(wl->window);
		wl->flags &= ~WINLINK_ALERTFLAGS;
		winlink_stack_remove(&s->lastw, wl);
		winlink_remove(&s->windows, wl);

		/* Force select/redraw if current. */
		if (wl == s->curw) {
			detached = 0;
			s->curw = NULL;
		}
	}

	if (args->argc == 0)
		cmd = options_get_string(&s->options, "default-command");
	else
		cmd = args->argv[0];
	cwd = cmd_get_default_path(ctx);

	if (idx == -1)
		idx = -1 - options_get_number(&s->options, "base-index");
	wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause);
	if (wl == NULL) {
		ctx->error(ctx, "create window failed: %s", cause);
		xfree(cause);
		return (-1);
	}
	if (!detached) {
		session_select(s, wl->idx);
		server_redraw_session_group(s);
	} else
		server_status_session_group(s);

	if (args_has(args, 'P'))
		ctx->print(ctx, "%s:%u", s->name, wl->idx);

	// TODO: Use a -F instead
	c = cmd_find_client(ctx, NULL);
	if (c && c->flags & CLIENT_CONTROL)
		ctx->print(ctx, "%u", wl->window->id);

	return (0);
}
Ejemplo n.º 8
0
int
mm_answer_pty(int sock, struct sshbuf *m)
{
	extern struct monitor *pmonitor;
	Session *s;
	int r, res, fd0;

	debug3("%s entering", __func__);

	sshbuf_reset(m);
	s = session_new();
	if (s == NULL)
		goto error;
	s->authctxt = authctxt;
	s->pw = authctxt->pw;
	s->pid = pmonitor->m_pid;
	res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
	if (res == 0)
		goto error;
	pty_setowner(authctxt->pw, s->tty);

	if ((r = sshbuf_put_u32(m, 1)) != 0 ||
	    (r = sshbuf_put_cstring(m, s->tty)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));

	/* We need to trick ttyslot */
	if (dup2(s->ttyfd, 0) == -1)
		fatal("%s: dup2", __func__);

	mm_record_login(s, authctxt->pw);

	/* Now we can close the file descriptor again */
	close(0);

	/* send messages generated by record_login */
	if ((r = sshbuf_put_stringb(m, loginmsg)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	sshbuf_reset(loginmsg);

	mm_request_send(sock, MONITOR_ANS_PTY, m);

	if (mm_send_fd(sock, s->ptyfd) == -1 ||
	    mm_send_fd(sock, s->ttyfd) == -1)
		fatal("%s: send fds failed", __func__);

	/* make sure nothing uses fd 0 */
	if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0)
		fatal("%s: open(/dev/null): %s", __func__, strerror(errno));
	if (fd0 != 0)
		error("%s: fd0 %d != 0", __func__, fd0);

	/* slave is not needed */
	close(s->ttyfd);
	s->ttyfd = s->ptyfd;
	/* no need to dup() because nobody closes ptyfd */
	s->ptymaster = s->ptyfd;

	debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ttyfd);

	return (0);

 error:
	if (s != NULL)
		mm_session_close(s);
	if ((r = sshbuf_put_u32(m, 0)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	mm_request_send(sock, MONITOR_ANS_PTY, m);
	return (0);
}
Ejemplo n.º 9
0
void session_upload_new(struct incident *i)
{
	GHashTableIter iter;
	gpointer key, value;
	GString *gstemp;
	struct session *session = NULL;
	char *url = NULL;

			
	if (incident_value_string_get(i, "_url", &gstemp) == false )
	{
		g_debug("dionaea.upload.request got no _url in incident!");
		return;
	}

	session = session_new();

	session->type = session_type_upload;

	url = gstemp->str;
	session->url = g_strdup(url);

	g_hash_table_iter_init (&iter, i->data);

	while( g_hash_table_iter_next (&iter, &key, &value) )
	{
		char *name = key;
		struct opaque_data *d = value;
		char name_and_param[1024];
		if( d->type == opaque_type_int )
		{
			g_warning("incident key %s has integer value. all post fields must be string values.", name);
		} else
		if( d->type == opaque_type_string)
		{
			/* ignore help field values */
			if( strstr(name, "_ct") != NULL ||
				strcmp(name, "_url") == 0)
				continue;

			if( strcmp(name, "_callback") == 0 )
			{ /* incident callback */
				session->action.upload.callback = g_strdup(d->opaque.string->str);
				session->action.upload.file = tempfile_new(curl_runtime.download_dir, "httpupload-");
			}else
			if( strcmp(name, "_userdata") == 0 )
			{ /* incident callback userdata */
				session->action.upload.userdata = g_strdup(d->opaque.string->str);
			}else
			if( strcmp(name, "user") == 0 )
			{ /* http auth user */
				session->action.upload.username = g_strdup(d->opaque.string->str);
				curl_easy_setopt(session->easy, CURLOPT_USERNAME, session->action.upload.username);
			}else
			if( strcmp(name, "pass") == 0 )
			{ /* http auth password */
				session->action.upload.password = g_strdup(d->opaque.string->str);
				curl_easy_setopt(session->easy, CURLOPT_PASSWORD, session->action.upload.password);
			}else
			if( strncmp(name, "file://", 7) == 0 )
			{ /* we upload this file */
				curl_formadd(&session->action.upload.formpost,
							 &session->action.upload.last,
							 CURLFORM_COPYNAME, name + 7,
							 CURLFORM_FILE, d->opaque.string->str,
							 CURLFORM_END);
			}else
			{ /* all other values */
				snprintf(name_and_param, 1024, "%s_ct", name);
				if ( incident_value_string_get(i, name_and_param, &gstemp) == true)
				{ /* with content type */
					curl_formadd(&session->action.upload.formpost,
								 &session->action.upload.last,
								 CURLFORM_COPYNAME, name,
								 CURLFORM_CONTENTTYPE, gstemp->str,
								 CURLFORM_COPYCONTENTS, d->opaque.string->str,
								 CURLFORM_END);
				} else
				{ /* without content type */
					curl_formadd(&session->action.upload.formpost,
								 &session->action.upload.last,
								 CURLFORM_COPYNAME, name,
								 CURLFORM_COPYCONTENTS, d->opaque.string->str,
								 CURLFORM_END);
				}
			}
		}
	}

	char buf[] = "Expect:";
	session->action.upload.headers = curl_slist_append(session->action.upload.headers, buf);


	curl_easy_setopt(session->easy, CURLOPT_URL, session->url);
	curl_easy_setopt(session->easy, CURLOPT_HTTPPOST, session->action.upload.formpost);
	curl_easy_setopt(session->easy, CURLOPT_HTTPHEADER, session->action.upload.headers);
	curl_easy_setopt(session->easy, CURLOPT_WRITEFUNCTION, curl_writefunction_cb);
	curl_easy_setopt(session->easy, CURLOPT_WRITEDATA, session);
	curl_easy_setopt(session->easy, CURLOPT_DEBUGFUNCTION, curl_debugfunction_cb);
//	curl_easy_setopt(session->easy, CURLOPT_VERBOSE, 1L);
	curl_easy_setopt(session->easy, CURLOPT_ERRORBUFFER, session->error);
	curl_easy_setopt(session->easy, CURLOPT_PRIVATE, session);
	curl_easy_setopt(session->easy, CURLOPT_NOPROGRESS, 0L);
	curl_easy_setopt(session->easy, CURLOPT_PROGRESSFUNCTION, curl_progressfunction_cb);
	curl_easy_setopt(session->easy, CURLOPT_PROGRESSDATA, session);
	curl_easy_setopt(session->easy, CURLOPT_LOW_SPEED_TIME, 3L);
	curl_easy_setopt(session->easy, CURLOPT_LOW_SPEED_LIMIT, 10L);
	curl_easy_setopt(session->easy, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
	curl_easy_setopt(session->easy, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(session->easy, CURLOPT_SSL_VERIFYHOST, 0);

	g_debug("Adding easy %p to multi %p (%s)", session->easy, curl_runtime.multi, url);
	curl_multi_add_handle(curl_runtime.multi, session->easy);
	curl_runtime.queued++;
	check_run_count();
}
Ejemplo n.º 10
0
/* This function is called from the protocol layer accept() in order to
 * instanciate a new session on behalf of a given listener and frontend. It
 * returns a positive value upon success, 0 if the connection can be ignored,
 * or a negative value upon critical failure. The accepted file descriptor is
 * closed if we return <= 0. If no handshake is needed, it immediately tries
 * to instanciate a new stream.
 */
int session_accept_fd(struct listener *l, int cfd, struct sockaddr_storage *addr)
{
	struct connection *cli_conn;
	struct proxy *p = l->frontend;
	struct session *sess;
	struct stream *strm;
	struct task *t;
	int ret;


	ret = -1; /* assume unrecoverable error by default */

	if (unlikely((cli_conn = conn_new()) == NULL))
		goto out_close;

	conn_prepare(cli_conn, l->proto, l->xprt);

	cli_conn->t.sock.fd = cfd;
	cli_conn->addr.from = *addr;
	cli_conn->flags |= CO_FL_ADDR_FROM_SET;
	cli_conn->target = &l->obj_type;
	cli_conn->proxy_netns = l->netns;

	conn_ctrl_init(cli_conn);

	/* wait for a PROXY protocol header */
	if (l->options & LI_O_ACC_PROXY) {
		cli_conn->flags |= CO_FL_ACCEPT_PROXY;
		conn_sock_want_recv(cli_conn);
	}

	conn_data_want_recv(cli_conn);
	if (conn_xprt_init(cli_conn) < 0)
		goto out_free_conn;

	sess = session_new(p, l, &cli_conn->obj_type);
	if (!sess)
		goto out_free_conn;

	p->feconn++;
	/* This session was accepted, count it now */
	if (p->feconn > p->fe_counters.conn_max)
		p->fe_counters.conn_max = p->feconn;

	proxy_inc_fe_conn_ctr(l, p);

	/* now evaluate the tcp-request layer4 rules. We only need a session
	 * and no stream for these rules.
	 */
	if ((l->options & LI_O_TCP_RULES) && !tcp_exec_req_rules(sess)) {
		/* let's do a no-linger now to close with a single RST. */
		setsockopt(cfd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
		ret = 0; /* successful termination */
		goto out_free_sess;
	}

	/* monitor-net and health mode are processed immediately after TCP
	 * connection rules. This way it's possible to block them, but they
	 * never use the lower data layers, they send directly over the socket,
	 * as they were designed for. We first flush the socket receive buffer
	 * in order to avoid emission of an RST by the system. We ignore any
	 * error.
	 */
	if (unlikely((p->mode == PR_MODE_HEALTH) ||
		     ((l->options & LI_O_CHK_MONNET) &&
		      addr->ss_family == AF_INET &&
		      (((struct sockaddr_in *)addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr))) {
		/* we have 4 possibilities here :
		 *  - HTTP mode, from monitoring address => send "HTTP/1.0 200 OK"
		 *  - HEALTH mode with HTTP check => send "HTTP/1.0 200 OK"
		 *  - HEALTH mode without HTTP check => just send "OK"
		 *  - TCP mode from monitoring address => just close
		 */
		if (l->proto->drain)
			l->proto->drain(cfd);
		if (p->mode == PR_MODE_HTTP ||
		    (p->mode == PR_MODE_HEALTH && (p->options2 & PR_O2_CHK_ANY) == PR_O2_HTTP_CHK))
			send(cfd, "HTTP/1.0 200 OK\r\n\r\n", 19, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE);
		else if (p->mode == PR_MODE_HEALTH)
			send(cfd, "OK\n", 3, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE);
		ret = 0;
		goto out_free_sess;
	}

	/* Adjust some socket options */
	if (l->addr.ss_family == AF_INET || l->addr.ss_family == AF_INET6) {
		setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one));

		if (p->options & PR_O_TCP_CLI_KA)
			setsockopt(cfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one));

		if (p->options & PR_O_TCP_NOLING)
			fdtab[cfd].linger_risk = 1;

#if defined(TCP_MAXSEG)
		if (l->maxseg < 0) {
			/* we just want to reduce the current MSS by that value */
			int mss;
			socklen_t mss_len = sizeof(mss);
			if (getsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &mss_len) == 0) {
				mss += l->maxseg; /* remember, it's < 0 */
				setsockopt(cfd, IPPROTO_TCP, TCP_MAXSEG, &mss, sizeof(mss));
			}
		}
#endif
	}

	if (global.tune.client_sndbuf)
		setsockopt(cfd, SOL_SOCKET, SO_SNDBUF, &global.tune.client_sndbuf, sizeof(global.tune.client_sndbuf));

	if (global.tune.client_rcvbuf)
		setsockopt(cfd, SOL_SOCKET, SO_RCVBUF, &global.tune.client_rcvbuf, sizeof(global.tune.client_rcvbuf));

	if (unlikely((t = task_new()) == NULL))
		goto out_free_sess;

	t->context = sess;
	t->nice = l->nice;

	/* OK, now either we have a pending handshake to execute with and
	 * then we must return to the I/O layer, or we can proceed with the
	 * end of the stream initialization. In case of handshake, we also
	 * set the I/O timeout to the frontend's client timeout.
	 *
	 * At this point we set the relation between sess/task/conn this way :
	 *
	 *          orig -- sess <-- context
	 *           |                   |
	 *           v                   |
	 *          conn -- owner ---> task
	 */
	if (cli_conn->flags & CO_FL_HANDSHAKE) {
		conn_attach(cli_conn, t, &sess_conn_cb);
		t->process = session_expire_embryonic;
		t->expire = tick_add_ifset(now_ms, p->timeout.client);
		task_queue(t);
		cli_conn->flags |= CO_FL_INIT_DATA | CO_FL_WAKE_DATA;
		return 1;
	}

	/* OK let's complete stream initialization since there is no handshake */
	cli_conn->flags |= CO_FL_CONNECTED;

	/* we want the connection handler to notify the stream interface about updates. */
	cli_conn->flags |= CO_FL_WAKE_DATA;

	/* if logs require transport layer information, note it on the connection */
	if (sess->fe->to_log & LW_XPRT)
		cli_conn->flags |= CO_FL_XPRT_TRACKED;

	session_count_new(sess);
	strm = stream_new(sess, t, &cli_conn->obj_type);
	if (!strm)
		goto out_free_task;

	strm->target        = sess->listener->default_target;
	strm->req.analysers = sess->listener->analysers;
	return 1;

 out_free_task:
	task_free(t);
 out_free_sess:
	p->feconn--;
	session_free(sess);
 out_free_conn:
	cli_conn->flags &= ~CO_FL_XPRT_TRACKED;
	conn_xprt_close(cli_conn);
	conn_free(cli_conn);
 out_close:
	if (ret < 0 && l->xprt == &raw_sock && p->mode == PR_MODE_HTTP) {
		/* critical error, no more memory, try to emit a 500 response */
		struct chunk *err_msg = &p->errmsg[HTTP_ERR_500];
		if (!err_msg->str)
			err_msg = &http_err_chunks[HTTP_ERR_500];
		send(cfd, err_msg->str, err_msg->len, MSG_DONTWAIT|MSG_NOSIGNAL);
	}

	if (fdtab[cfd].owner)
		fd_delete(cfd);
	else
		close(cfd);
	return ret;
}