]> jfr.im git - solanum.git/blobdiff - authd/providers/ident.c
authd: Cleanup
[solanum.git] / authd / providers / ident.c
index d633d17269f36901bee06f949e8c35fd56ffc480..357bc74de69ce91ef320e2be83186f798e474d4e 100644 (file)
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+/* Largely adapted from old s_auth.c, but reworked for authd. rDNS code
+ * moved to its own provider.
+ *
+ * --Elizafox 13 March 2016
+ */
+
 #include "stdinc.h"
 #include "match.h"
 #include "authd.h"
+#include "notice.h"
 #include "provider.h"
 #include "res.h"
 
@@ -28,9 +35,6 @@
 
 struct ident_query
 {
-       rb_dlink_node node;
-
-       struct auth_client *auth;               /* Our client */
        time_t timeout;                         /* Timeout interval */
        rb_fde_t *F;                            /* Our FD */
 };
@@ -38,9 +42,11 @@ struct ident_query
 /* Goinked from old s_auth.c --Elizafox */
 static const char *messages[] =
 {
-       ":*** Checking Ident",
-       ":*** Got Ident response",
-       ":*** No Ident response",
+       "*** Checking Ident",
+       "*** Got Ident response",
+       "*** No Ident response",
+       "*** Cannot verify ident validity, ignoring ident",
+       "*** Ident disabled, not checking ident",
 };
 
 typedef enum
@@ -48,137 +54,36 @@ typedef enum
        REPORT_LOOKUP,
        REPORT_FOUND,
        REPORT_FAIL,
+       REPORT_INVALID,
+       REPORT_DISABLED,
 } ident_message;
 
 static EVH timeout_ident_queries_event;
 static CNCB ident_connected;
 static PF read_ident_reply;
 
-static void client_fail(struct ident_query *query, ident_message message);
-static void client_success(struct ident_query *query);
-static void cleanup_query(struct ident_query *query);
+static void client_fail(struct auth_client *auth, ident_message message);
+static void client_success(struct auth_client *auth);
 static char * get_valid_ident(char *buf);
 
-static rb_dlink_list queries;
 static struct ev_entry *timeout_ev;
 static int ident_timeout = 5;
+static bool ident_enable = true;
 
 
-bool ident_init(void)
-{
-       timeout_ev = rb_event_addish("timeout_ident_queries_event", timeout_ident_queries_event, NULL, 1);
-       return (timeout_ev != NULL);
-}
-
-void ident_destroy(void)
-{
-       rb_dlink_node *ptr, *nptr;
-
-       /* Nuke all ident queries */
-       RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head)
-       {
-               struct ident_query *query = ptr->data;
-
-               notice_client(query->auth, messages[REPORT_FAIL]);
-
-               rb_close(query->F);
-               rb_free(query);
-               rb_dlinkDelete(ptr, &queries);
-       }
-}
-
-bool ident_start(struct auth_client *auth)
-{
-       struct ident_query *query = rb_malloc(sizeof(struct ident_query));
-       struct rb_sockaddr_storage l_addr, c_addr;
-       int family;
-       rb_fde_t *F;
-
-       query->auth = auth;
-       query->timeout = rb_current_time() + ident_timeout;
-
-       if((F = rb_socket(family, SOCK_STREAM, 0, "ident")) == NULL)
-       {
-               client_fail(query, REPORT_FAIL);
-               return true;    /* Not a fatal error */
-       }
-
-       query->F = F;
-
-       /* Build sockaddr_storages for rb_connect_tcp below */
-       if(!rb_inet_ntop_sock((struct sockaddr *)&l_addr, auth->l_ip, sizeof(l_addr)) ||
-               !rb_inet_ntop_sock((struct sockaddr *)&c_addr, auth->c_ip, sizeof(c_addr)))
-       {
-               client_fail(query, REPORT_FAIL);
-               return true;
-       }
-
-       /* Set the ports correctly */
-#ifdef RB_IPV6
-       if(GET_SS_FAMILY(&l_addr) == AF_INET6)
-               ((struct sockaddr_in6 *)&l_addr)->sin6_port = 0;
-       else
-#endif
-               ((struct sockaddr_in *)&l_addr)->sin_port = 0;
-
-#ifdef RB_IPV6
-       if(GET_SS_FAMILY(&c_addr) == AF_INET6)
-               ((struct sockaddr_in6 *)&c_addr)->sin6_port = htons(113);
-       else
-#endif
-               ((struct sockaddr_in *)&c_addr)->sin_port = htons(113);
-
-       rb_connect_tcp(F, (struct sockaddr *)&c_addr,
-                       (struct sockaddr *)&l_addr,
-                       GET_SS_LEN(&l_addr), ident_connected,
-                       query, ident_timeout);
-
-       rb_dlinkAdd(query, &query->node, &queries);
-
-       set_provider(auth, PROVIDER_IDENT);
-       notice_client(auth, messages[REPORT_LOOKUP]);
-
-       return true;
-}
-
-void ident_cancel(struct auth_client *auth)
-{
-       rb_dlink_node *ptr, *nptr;
-
-       RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head)
-       {
-               struct ident_query *query = ptr->data;
-
-               if(query->auth == auth)
-               {
-                       client_fail(query, REPORT_FAIL);
-
-                       rb_close(query->F);
-                       rb_free(query);
-                       rb_dlinkDelete(ptr, &queries);
-
-                       return;
-               }
-       }
-}
-
 /* Timeout outstanding queries */
-static void timeout_ident_queries_event(void *notused)
+static void
+timeout_ident_queries_event(void *notused __unused)
 {
-       rb_dlink_node *ptr, *nptr;
+       struct auth_client *auth;
+       rb_dictionary_iter iter;
 
-       RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head)
+       RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
        {
-               struct ident_query *query = ptr->data;
+               struct ident_query *query = auth->data[PROVIDER_IDENT];
 
-               if(query->timeout < rb_current_time())
-               {
-                       client_fail(query, REPORT_FAIL);
-
-                       rb_close(query->F);
-                       rb_free(query);
-                       rb_dlinkDelete(ptr, &queries);
-               }
+               if(query != NULL && query->timeout < rb_current_time())
+                       client_fail(auth, REPORT_FAIL);
        }
 }
 
@@ -193,19 +98,27 @@ static void timeout_ident_queries_event(void *notused)
  * a write buffer far greater than this message to store it in should
  * problems arise. -avalon
  */
-static void ident_connected(rb_fde_t *F, int error, void *data)
+static void
+ident_connected(rb_fde_t *F __unused, int error, void *data)
 {
-       struct ident_query *query = data;
-       struct auth_client *auth = query->auth;
+       struct auth_client *auth = data;
+       struct ident_query *query;
        char authbuf[32];
        int authlen;
 
+       if(auth == NULL)
+               return;
+
+       query = auth->data[PROVIDER_IDENT];
+
+       if(query == NULL)
+               return;
+
        /* Check the error */
        if(error != RB_OK)
        {
                /* We had an error during connection :( */
-               client_fail(query, REPORT_FAIL);
-               cleanup_query(query);
+               client_fail(auth, REPORT_FAIL);
                return;
        }
 
@@ -215,36 +128,43 @@ static void ident_connected(rb_fde_t *F, int error, void *data)
 
        if(rb_write(query->F, authbuf, authlen) != authlen)
        {
-               client_fail(query, REPORT_FAIL);
+               client_fail(auth, REPORT_FAIL);
                return;
        }
 
-       read_ident_reply(query->F, query);
+       read_ident_reply(query->F, auth);
 }
 
 static void
 read_ident_reply(rb_fde_t *F, void *data)
 {
-       struct ident_query *query = data;
-       struct auth_client *auth = query->auth;
+       struct auth_client *auth = data;
+       struct ident_query *query;
+       char buf[IDENT_BUFSIZE + 1];    /* buffer to read auth reply into */
+       ident_message message = REPORT_FAIL;
        char *s = NULL;
        char *t = NULL;
-       int len;
+       ssize_t len;
        int count;
-       char buf[IDENT_BUFSIZE + 1];    /* buffer to read auth reply into */
+
+       if(auth == NULL)
+               return;
+
+       query = auth->data[PROVIDER_IDENT];
+
+       if(query == NULL)
+               return;
 
        len = rb_read(F, buf, IDENT_BUFSIZE);
        if(len < 0 && rb_ignore_errno(errno))
        {
-               rb_setselect(F, RB_SELECT_READ, read_ident_reply, query);
+               rb_setselect(F, RB_SELECT_READ, read_ident_reply, auth);
                return;
        }
 
        if(len > 0)
        {
-               buf[len] = '\0';
-
-               if((s = get_valid_ident(buf)))
+               if((s = get_valid_ident(buf)) != NULL)
                {
                        t = auth->username;
 
@@ -253,10 +173,9 @@ read_ident_reply(rb_fde_t *F, void *data)
 
                        for (count = USERLEN; *s && count; s++)
                        {
-                               if(*s == '@')
-                               {
+                               if(*s == '@' || *s == '\r' || *s == '\n')
                                        break;
-                               }
+
                                if(*s != ' ' && *s != ':' && *s != '[')
                                {
                                        *t++ = *s;
@@ -265,61 +184,58 @@ read_ident_reply(rb_fde_t *F, void *data)
                        }
                        *t = '\0';
                }
+               else
+                       message = REPORT_INVALID;
        }
 
        if(s == NULL)
-               client_fail(query, REPORT_FAIL);
+               client_fail(auth, message);
        else
-               client_success(query);
-
-       cleanup_query(query);
+               client_success(auth);
 }
 
-static void client_fail(struct ident_query *query, ident_message report)
+static void
+client_fail(struct auth_client *auth, ident_message report)
 {
-       struct auth_client *auth = query->auth;
+       struct ident_query *query = auth->data[PROVIDER_IDENT];
 
-       if(auth)
-       {
-               rb_strlcpy(auth->username, "*", sizeof(auth->username));
-               notice_client(auth, messages[report]);
-               provider_done(auth, PROVIDER_IDENT);
-       }
-}
+       if(query == NULL)
+               return;
 
-static void client_success(struct ident_query *query)
-{
-       struct auth_client *auth = query->auth;
+       rb_strlcpy(auth->username, "*", sizeof(auth->username));
 
-       if(auth)
-       {
-               notice_client(auth, messages[REPORT_FOUND]);
-               provider_done(auth, PROVIDER_IDENT);
-       }
+       if(query->F != NULL)
+               rb_close(query->F);
+
+       rb_free(query);
+       auth->data[PROVIDER_IDENT] = NULL;
+
+       notice_client(auth->cid, messages[report]);
+       provider_done(auth, PROVIDER_IDENT);
 }
 
-static void cleanup_query(struct ident_query *query)
+static void
+client_success(struct auth_client *auth)
 {
-       rb_dlink_node *ptr, *nptr;
+       struct ident_query *query = auth->data[PROVIDER_IDENT];
 
-       RB_DLINK_FOREACH_SAFE(ptr, nptr, queries.head)
-       {
-               struct ident_query *query_l = ptr->data;
+       if(query == NULL)
+               return;
 
-               if(query_l == query)
-               {
-                       rb_close(query->F);
-                       rb_free(query);
-                       rb_dlinkDelete(ptr, &queries);
-               }
-       }
+       if(query->F != NULL)
+               rb_close(query->F);
+
+       rb_free(query);
+       auth->data[PROVIDER_IDENT] = NULL;
+
+       notice_client(auth->cid, messages[REPORT_FOUND]);
+       provider_done(auth, PROVIDER_IDENT);
 }
 
 /* get_valid_ident
  * parse ident query reply from identd server
  *
- * Torn out of old s_auth.c because there was nothing wrong with it
- * --Elizafox
+ * Taken from old s_auth.c --Elizafox
  *
  * Inputs      - pointer to ident buf
  * Outputs     - NULL if no valid ident found, otherwise pointer to name
@@ -341,45 +257,161 @@ get_valid_ident(char *buf)
 
        colon1Ptr = strchr(remotePortString, ':');
        if(!colon1Ptr)
-               return 0;
+               return NULL;
 
        *colon1Ptr = '\0';
        colon1Ptr++;
        colon2Ptr = strchr(colon1Ptr, ':');
        if(!colon2Ptr)
-               return 0;
+               return NULL;
 
        *colon2Ptr = '\0';
        colon2Ptr++;
        commaPtr = strchr(remotePortString, ',');
 
        if(!commaPtr)
-               return 0;
+               return NULL;
 
        *commaPtr = '\0';
        commaPtr++;
 
        remp = atoi(remotePortString);
        if(!remp)
-               return 0;
+               return NULL;
 
        locp = atoi(commaPtr);
        if(!locp)
-               return 0;
+               return NULL;
 
        /* look for USERID bordered by first pair of colons */
        if(!strstr(colon1Ptr, "USERID"))
-               return 0;
+               return NULL;
 
        colon3Ptr = strchr(colon2Ptr, ':');
        if(!colon3Ptr)
-               return 0;
+               return NULL;
 
        *colon3Ptr = '\0';
        colon3Ptr++;
        return (colon3Ptr);
 }
 
+static bool
+ident_init(void)
+{
+       timeout_ev = rb_event_addish("timeout_ident_queries_event", timeout_ident_queries_event, NULL, 1);
+       return (timeout_ev != NULL);
+}
+
+static void
+ident_destroy(void)
+{
+       struct auth_client *auth;
+       rb_dictionary_iter iter;
+
+       /* Nuke all ident queries */
+       RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
+       {
+               if(auth->data[PROVIDER_IDENT] != NULL)
+                       client_fail(auth, REPORT_FAIL);
+       }
+}
+
+static bool ident_start(struct auth_client *auth)
+{
+       struct ident_query *query = rb_malloc(sizeof(struct ident_query));
+       struct rb_sockaddr_storage l_addr, c_addr;
+       int family = GET_SS_FAMILY(&auth->c_addr);
+
+       if(auth->data[PROVIDER_IDENT] != NULL)
+       {
+               set_provider_done(auth, PROVIDER_IDENT); /* for blacklists */
+               return true;
+       }
+       else if(!ident_enable)
+       {
+               notice_client(auth->cid, messages[REPORT_DISABLED]);
+               set_provider_done(auth, PROVIDER_IDENT);
+               return true;
+       }
+
+       notice_client(auth->cid, messages[REPORT_LOOKUP]);
+
+       auth->data[PROVIDER_IDENT] = query;
+       query->timeout = rb_current_time() + ident_timeout;
+
+       if((query->F = rb_socket(family, SOCK_STREAM, 0, "ident")) == NULL)
+       {
+               warn_opers(L_DEBUG, "Could not create ident socket: %s", strerror(errno));
+               client_fail(auth, REPORT_FAIL);
+               return true;    /* Not a fatal error */
+       }
+
+       /* Build sockaddr_storages for rb_connect_tcp below */
+       memcpy(&l_addr, &auth->l_addr, sizeof(l_addr));
+       memcpy(&c_addr, &auth->c_addr, sizeof(c_addr));
+
+       /* Set the ports correctly */
+#ifdef RB_IPV6
+       if(GET_SS_FAMILY(&l_addr) == AF_INET6)
+               ((struct sockaddr_in6 *)&l_addr)->sin6_port = 0;
+       else
+#endif
+               ((struct sockaddr_in *)&l_addr)->sin_port = 0;
+
+#ifdef RB_IPV6
+       if(GET_SS_FAMILY(&c_addr) == AF_INET6)
+               ((struct sockaddr_in6 *)&c_addr)->sin6_port = htons(113);
+       else
+#endif
+               ((struct sockaddr_in *)&c_addr)->sin_port = htons(113);
+
+       rb_connect_tcp(query->F, (struct sockaddr *)&c_addr,
+                       (struct sockaddr *)&l_addr,
+                       GET_SS_LEN(&l_addr), ident_connected,
+                       auth, ident_timeout);
+
+       set_provider_on(auth, PROVIDER_IDENT);
+
+       return true;
+}
+
+static void
+ident_cancel(struct auth_client *auth)
+{
+       struct ident_query *query = auth->data[PROVIDER_IDENT];
+
+       if(query != NULL)
+               client_fail(auth, REPORT_FAIL);
+}
+
+static void
+add_conf_ident_timeout(const char *key __unused, int parc __unused, const char **parv)
+{
+       int timeout = atoi(parv[0]);
+
+       if(timeout < 0)
+       {
+               warn_opers(L_CRIT, "BUG: ident timeout < 0 (value: %d)", timeout);
+               return;
+       }
+
+       ident_timeout = timeout;
+}
+
+static void
+set_ident_enabled(const char *key __unused, int parc __unused, const char **parv)
+{
+       ident_enable = (*parv[0] == '1');
+}
+
+struct auth_opts_handler ident_options[] =
+{
+       { "ident_timeout", 1, add_conf_ident_timeout },
+       { "ident_enabled", 1, set_ident_enabled },
+       { NULL, 0, NULL },
+};
+
 
 struct auth_provider ident_provider =
 {
@@ -389,4 +421,5 @@ struct auth_provider ident_provider =
        .start = ident_start,
        .cancel = ident_cancel,
        .completed = NULL,
+       .opt_handlers = ident_options,
 };