commit 4eaa2fcd79d72de0bdf6afa8566189c34f152ef4
Author: Nam <nam@lqhn.net>
Date:   Thu Aug 5 19:51:36 2010 +0900

    Add IP restrictions

diff --git a/db.c b/db.c
index 3ad7eb3..a0d278e 100644
--- a/db.c
+++ b/db.c
@@ -4674,6 +4674,79 @@ int db_getmailbox_list_result(u64_t mailbox_idnr, u64_t user_idnr, mailbox_t * m
        return DM_SUCCESS;
 }

+int db_check_ip_restrictions(int service, clientinfo_t *ci, char *username)
+{
+       char clientsock[DM_SOCKADDR_LEN];
+       char * escaped_username;
+       const char *userid = NULL, *sockok = NULL, *sockno = NULL, *client = NULL;
+       unsigned row, bestrow = 0;
+       int result;
+       int score, not_allow = 0;
+       char query[DEF_QUERYSIZE];
+       char service_text[5];
+
+       memset(query,0,DEF_QUERYSIZE);
+       memset(clientsock,0,DM_SOCKADDR_LEN);
+
+       TRACE(TRACE_DEBUG,"Checking restrictions of [%s]", username);
+
+       if (ci==NULL) {
+               strncpy(clientsock,"",1);
+       } else {
+               snprintf(clientsock, DM_SOCKADDR_LEN, "inet:%s", ci->ip_src);
+               TRACE(TRACE_DEBUG, "client on inet socket [%s]", clientsock);
+       }
+
+       escaped_username = dm_stresc(username);
+
+       /* Get sockets */
+       if (service == 0) strcpy(service_text, "pop");
+       else strcpy(service_text, "imap");
+       snprintf(query, DEF_QUERYSIZE, "SELECT u.userid, u.client_idnr, r.hosts_deny, r.hosts_allow FROM %susers u "
+               "LEFT JOIN %srestrictions r USING(client_idnr) "
+               "WHERE r.service = '%s' AND u.userid = '%s' "
+               "ORDER BY hosts_allow DESC",
+               DBPFX, DBPFX, service_text, escaped_username);
+
+       g_free(escaped_username);
+
+       if (db_query(query) == -1) {
+               TRACE(TRACE_ERROR, "Could not select restrictions");
+               return DM_SUCCESS;
+       }
+
+       if (db_num_rows() == 0) {
+               /* No restrictions */
+               TRACE(TRACE_DEBUG, "No restrictions for [%s]", username);
+               db_free_result();
+               return DM_SUCCESS;
+       }
+
+       /* find the best match on the usermap table */
+       for (row=0; row < db_num_rows(); row++) {
+               userid = db_get_result(row, 0);
+               client = db_get_result(row, 1);
+               sockno = db_get_result(row, 2);
+               sockok = db_get_result(row, 3);
+               result = dm_sock_score(sockok, clientsock);
+               /* any match on sockok will be ok */
+               if (result) {
+                       db_free_result();
+                       return DM_SUCCESS;
+               }
+               score = dm_sock_score(sockno, clientsock);
+               if (!not_allow && score) {
+                       not_allow = 1;
+               }
+       }
+
+       db_free_result();
+
+       TRACE(TRACE_DEBUG, "not_allow: [%d]", not_allow);
+       if (not_allow == 0) return DM_SUCCESS; // no match at all.
+       return DM_EGENERAL;
+}
+
 int db_usermap_resolve(clientinfo_t *ci, const char *username, char *real_username)
 {
        struct sockaddr saddr;
@@ -4779,6 +4852,7 @@ int db_usermap_resolve(clientinfo_t *ci, const char *username, char *real_userna
        return DM_SUCCESS;

 }
+
 int db_user_exists(const char *username, u64_t * user_idnr)
 {
        const char *query_result;
diff --git a/db.h b/db.h
index b5fdd6d..d4812b9 100644
--- a/db.h
+++ b/db.h
@@ -1316,4 +1316,13 @@ int db_count_replycache(timestring_t lasttokeep, u64_t *affected_rows);
 /* get driver specific SQL snippets */
 const char * db_get_sql(sql_fragment_t frag);

+/* check IP restrictions
+ param service number
+       0: POP
+       1: IMAP (not implemented)
+ return
+       0: user is allowed to use service from IP
+       1: NOT allowed
+*/
+int db_check_ip_restrictions(int service, clientinfo_t *ci, char *username);
 #endif
diff --git a/pop3.c b/pop3.c
index 3d8f4f9..f47a12f 100644
--- a/pop3.c
+++ b/pop3.c
@@ -378,6 +378,23 @@ int pop3(clientinfo_t *ci, char *buffer, PopSession_t * session)
                        strncpy(session->username, value, strlen(value) + 1);
                }

+               /* check ip restrictions for POP */
+               validate_result = db_check_ip_restrictions(0, ci, session->username);
+               switch (validate_result) {
+                       case 0:
+                               TRACE(TRACE_DEBUG, "user [%s] from [%s] is allowed\n",
+                                       session->username,
+                                       ci->ip_src);
+                               break;
+                       case 1:
+                               TRACE(TRACE_ERROR, "user [%s] from [%s] is NOT allowed\n",
+                                       session->username,
+                                       ci->ip_src);
+                               session->SessionResult = 5;
+                               ci_write((FILE *) stream, "-ERR Your account is NOT allowed to use POP from current IP.\r\n");
+                               return -3;
+               }
+
                ci_write((FILE *) stream, "+OK Password required for %s\r\n", session->username);
                return 1;
