#include "list.h"
#include "msg.h" /* for MAXPARA */
#include "numeric.h"
+#include "numnicks.h"
#include "querycmds.h"
#include "random.h"
#include "res.h"
return 1; /* it's a valid hostname */
}
+/** Check whether a client already has a CONF_CLIENT configuration
+ * item.
+ *
+ * @return A pointer to the client's first CONF_CLIENT, or NULL if
+ * there are none.
+ */
+static struct ConfItem *find_conf_client(struct Client *cptr)
+{
+ struct SLink *list;
+
+ for (list = cli_confs(cptr); list != NULL; list = list->next) {
+ struct ConfItem *aconf;
+ aconf = list->value.aconf;
+ if (aconf->status & CONF_CLIENT)
+ return aconf;
+ }
+
+ return NULL;
+}
+
/** Assign a client to a connection class.
* @param[in] cptr Client to assign to a class.
* @return Zero if client is kept, CPTR_KILLED if rejected.
ircd_strncpy(cli_user(cptr)->host, cli_sockhost(cptr), HOSTLEN);
ircd_strncpy(cli_user(cptr)->realhost, cli_sockhost(cptr), HOSTLEN);
+ if (find_conf_client(cptr)) {
+ return 0;
+ }
+
switch (conf_check_client(cptr))
{
case ACR_OK:
/* Check for iauth timeout. */
if (FlagHas(&auth->flags, AR_IAUTH_PENDING)) {
- sendto_iauth(cptr, "T");
if (IAuthHas(iauth, IAUTH_REQUIRED)) {
sendheader(cptr, REPORT_FAIL_IAUTH);
return exit_client_msg(cptr, cptr, &me, "Authorization Timeout");
}
+ sendto_iauth(cptr, "T");
FlagClr(&auth->flags, AR_IAUTH_PENDING);
return check_auth_finished(auth);
}
sendto_iauth(cptr, "D");
}
+/** Forward an XREPLY on to iauth.
+ * @param[in] sptr Source of the XREPLY.
+ * @param[in] routing Routing information for the original XQUERY.
+ * @param[in] reply Contents of the reply.
+ */
+void auth_send_xreply(struct Client *sptr, const char *routing,
+ const char *reply)
+{
+ sendto_iauth(NULL, "X %#C %s :%s", sptr, routing, reply);
+}
+
/** Mark that a user has started capabilities negotiation.
* This blocks authorization until auth_cap_done() is called.
* @param[in] auth Authorization request for client.
/* Attempt to allocate a pair of sockets. */
res = os_socketpair(s_io);
- if (res)
- return errno;
+ if (res) {
+ res = errno;
+ Debug((DEBUG_INFO, "Unable to create IAuth socketpair: %s", strerror(res)));
+ return res;
+ }
/* Mark the parent's side of the pair (element 0) as non-blocking. */
res = os_set_nonblocking(s_io[0]);
if (!res) {
res = errno;
+ Debug((DEBUG_INFO, "Unable to make IAuth socket non-blocking: %s", strerror(res)));
close(s_io[1]);
close(s_io[0]);
return res;
SS_CONNECTED, SOCK_EVENT_READABLE, s_io[0]);
if (!res) {
res = errno;
+ Debug((DEBUG_INFO, "Unable to register IAuth socket: %s", strerror(res)));
close(s_io[1]);
close(s_io[0]);
return res;
res = os_socketpair(s_err);
if (res) {
res = errno;
+ Debug((DEBUG_INFO, "Unable to create IAuth stderr: %s", strerror(res)));
socket_del(i_socket(iauth));
close(s_io[1]);
close(s_io[0]);
res = os_set_nonblocking(s_err[0]);
if (!res) {
res = errno;
+ Debug((DEBUG_INFO, "Unable to make IAuth stderr non-blocking: %s", strerror(res)));
close(s_err[1]);
close(s_err[0]);
socket_del(i_socket(iauth));
SS_CONNECTED, SOCK_EVENT_READABLE, s_err[0]);
if (!res) {
res = errno;
+ Debug((DEBUG_INFO, "Unable to register IAuth stderr: %s", strerror(res)));
close(s_err[1]);
close(s_err[0]);
socket_del(i_socket(iauth));
if (cpid < 0) {
/* Error forking the child, still in parent. */
res = errno;
+ Debug((DEBUG_INFO, "Unable to fork IAuth child: %s", strerror(res)));
socket_del(i_stderr(iauth));
close(s_err[1]);
close(s_err[0]);
same = 0;
}
/* Check that we have no more pre-existing arguments. */
- if (iauth->i_argv[ii])
+ if (same && iauth->i_argv[ii])
same = 0;
- /* If they are the same and still connected, clear the "closing" flag and exit.*/
+ /* If they are the same and still connected, clear the "closing" flag and exit. */
if (same && i_GetConnected(iauth)) {
+ Debug((DEBUG_INFO, "Reusing existing IAuth process"));
IAuthClr(iauth, IAUTH_CLOSING);
return 2;
}
- /* Deallocate old argv elements. */
- for (ii = 0; iauth->i_argv[ii]; ++ii)
- MyFree(iauth->i_argv[ii]);
- MyFree(iauth->i_argv);
+ auth_close_unused();
}
/* Need to initialize a new connection. */
}
/* Set hostname from params. */
ircd_strncpy(cli_sockhost(cli), params[0], HOSTLEN);
+ /* If we have gotten here, the user is in a "hurry" state and has
+ * been pre-registered. Their hostname was set during that, and
+ * needs to be overwritten now.
+ */
+ if (FlagHas(&auth->flags, AR_IAUTH_HURRY)) {
+ ircd_strncpy(cli_user(cli)->host, cli_sockhost(cli), HOSTLEN);
+ ircd_strncpy(cli_user(cli)->realhost, cli_sockhost(cli), HOSTLEN);
+ }
return 1;
}
/* Make sure the configuration class is valid. */
class = find_class(class_name);
- if (!class)
+ if (!class || !class->valid)
return NULL;
/* Look for an existing ConfItem for the class. */
ConClass(class));
return NULL;
}
+ /* make_conf() "helpfully" links the conf into GlobalConfList,
+ * which we do not want, so undo that. (Ugh.)
+ */
+ if (aconf == GlobalConfList) {
+ GlobalConfList = aconf->next;
+ }
+ /* Back to business as usual. */
aconf->conn_class = class;
aconf->next = aconf_list;
aconf_list = aconf;
* @param[in] cli Client referenced by command.
* @param[in] parc Number of parameters.
* @param[in] params Optional class name for client.
- * @return One.
+ * @return Negative (CPTR_KILLED) if the connection is refused, one otherwise.
*/
static int iauth_cmd_done_client(struct IAuth *iauth, struct Client *cli,
int parc, char **params)
struct ConfItem *aconf;
aconf = auth_find_class_conf(params[0]);
- if (aconf)
- attach_conf(cli, aconf);
- else
+ if (aconf) {
+ enum AuthorizationCheckResult acr;
+
+ acr = attach_conf(cli, aconf);
+ switch (acr) {
+ case ACR_OK:
+ /* There should maybe be some way to set FLAG_DOID here.. */
+ break;
+ case ACR_TOO_MANY_IN_CLASS:
+ ++ServerStats->is_ref;
+ return exit_client(cli, cli, &me,
+ "Sorry, your connection class is full - try "
+ "again later or try another server");
+ default:
+ log_write(LS_IAUTH, L_ERROR, 0, "IAuth: Unexpected AuthorizationCheckResult %d from attach_conf()", acr);
+ break;
+ }
+ } else
sendto_opmask_butone_ratelimited(NULL, SNO_AUTH, &warn_time,
"iauth tried to use undefined class [%s]",
params[0]);
* @param[in] cli Client referenced by command.
* @param[in] parc Number of parameters.
* @param[in] params Account name and optional class name for client.
- * @return Non-zero if \a cli authorization should be checked for completion.
+ * @return Negative if the connection is refused, otherwise non-zero
+ * if \a cli authorization should be checked for completion.
*/
static int iauth_cmd_done_account(struct IAuth *iauth, struct Client *cli,
int parc, char **params)
return 0;
}
+/** Send an extension query to a specified remote server.
+ * @param[in] iauth Active IAuth session.
+ * @param[in] cli Client referenced by command.
+ * @param[in] parc Number of parameters (3).
+ * @param[in] params Remote server, routing information, and query.
+ * @return Zero.
+ */
+static int iauth_cmd_xquery(struct IAuth *iauth, struct Client *cli,
+ int parc, char **params)
+{
+ const char *serv;
+ const char *routing;
+ const char *query;
+ struct Client *acptr;
+
+ /* Process parameters */
+ if (EmptyString(params[0])) {
+ sendto_iauth(cli, "E Missing :Missing server parameter");
+ return 0;
+ } else
+ serv = params[0];
+
+ if (EmptyString(params[1])) {
+ sendto_iauth(cli, "E Missing :Missing routing parameter");
+ return 0;
+ } else
+ routing = params[1];
+
+ if (EmptyString(params[2])) {
+ sendto_iauth(cli, "E Missing :Missing query parameter");
+ return 0;
+ } else
+ query = params[2];
+
+ /* Try to find the specified server */
+ if (!(acptr = find_match_server(serv))) {
+ sendto_iauth(cli, "x %s %s :Server not online", serv, routing);
+ return 0;
+ }
+
+ /* If it's to us, do nothing; otherwise, forward the query */
+ if (!IsMe(acptr))
+ /* The "iauth:" prefix helps ircu route the reply to iauth */
+ sendcmdto_one(&me, CMD_XQUERY, acptr, "%C iauth:%s :%s", acptr, routing,
+ query);
+
+ return 0;
+}
+
/** Parse a \a message from \a iauth.
* @param[in] iauth Active IAuth session.
* @param[in] message Message to be parsed.
case 'A': handler = iauth_cmd_config; has_cli = 0; break;
case 's': handler = iauth_cmd_newstats; has_cli = 0; break;
case 'S': handler = iauth_cmd_stats; has_cli = 0; break;
+ case 'X': handler = iauth_cmd_xquery; has_cli = 0; break;
case 'o': handler = iauth_cmd_username_forced; has_cli = 1; break;
case 'U': handler = iauth_cmd_username_good; has_cli = 1; break;
case 'u': handler = iauth_cmd_username_bad; has_cli = 1; break;
/* Report mismatch to iauth. */
sendto_iauth(cli, "E Mismatch :[%s] != [%s]", params[1],
ircd_ntoa(&cli_ip(cli)));
- else if (handler(iauth, cli, parc - 3, params + 3))
+ else if (handler(iauth, cli, parc - 3, params + 3) > 0)
/* Handler indicated a possible state change. */
check_auth_finished(auth);
}