|
From: <pdo...@us...> - 2010-07-25 05:01:07
|
Revision: 13984
http://squirrelmail.svn.sourceforge.net/squirrelmail/?rev=13984&view=rev
Author: pdontthink
Date: 2010-07-25 05:01:00 +0000 (Sun, 25 Jul 2010)
Log Message:
-----------
Committing IMAP proxy version 1.1
Added Paths:
-----------
trunk/imap_proxy/
trunk/imap_proxy/Makefile
trunk/imap_proxy/README
trunk/imap_proxy/include/
trunk/imap_proxy/include/common.h
trunk/imap_proxy/include/imapproxy.h
trunk/imap_proxy/scripts/
trunk/imap_proxy/scripts/imapproxy
trunk/imap_proxy/scripts/imapproxy.conf
trunk/imap_proxy/src/
trunk/imap_proxy/src/becomenonroot.c
trunk/imap_proxy/src/config.c
trunk/imap_proxy/src/hash.c
trunk/imap_proxy/src/icc.c
trunk/imap_proxy/src/imapcommon.c
trunk/imap_proxy/src/main.c
trunk/imap_proxy/src/pimpstat.c
trunk/imap_proxy/src/request.c
Added: trunk/imap_proxy/Makefile
===================================================================
--- trunk/imap_proxy/Makefile (rev 0)
+++ trunk/imap_proxy/Makefile 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,64 @@
+#### Makefile for IMAP proxy
+#### Contributed by Gary Mills <mi...@cc...>
+
+## Tuneables
+
+# Paths
+
+INSTALL = /usr/ucb/install
+EBIN = /usr/local/sbin
+MAN = /usr/local/man/man
+ETC = /etc
+
+# Compiler flags
+CC = gcc
+RANLIB = :
+CFLAGS = -I./include
+LDLIBS =
+
+# Man sections
+MANLIB = 3
+MANADM = 1m
+
+## Nothing to change after this point
+
+# Libraries
+
+XYD_LIB = -lpthread -lmd5 -lsocket -lnsl
+TAT_LIB = -lcurses
+
+# Object files
+
+XYD_OBJ = ./src/icc.o ./src/main.o ./src/imapcommon.o ./src/request.o ./src/hash.o ./src/becomenonroot.o ./src/config.o
+TAT_OBJ = ./src/pimpstat.o ./src/config.o
+
+# Final targets
+
+XYD_BIN = ./bin/in.imapproxyd
+TAT_BIN = ./bin/pimpstat
+
+# Rules
+
+all: $(XYD_BIN) $(TAT_BIN)
+
+$(XYD_OBJ) $(TAT_OBJ): $(MAKEFILE) ./include/common.h ./include/imapproxy.h
+
+$(XYD_BIN): $(XYD_OBJ)
+ $(CC) -o $@ $(XYD_OBJ) $(XYD_LIB)
+
+$(TAT_BIN): $(TAT_OBJ)
+ $(CC) -o $@ $(TAT_OBJ) $(TAT_LIB)
+
+clean:
+ rm -f ./src/core ./src/$(XYD_OBJ) ./src/$(TAT_OBJ) $(XYD_BIN) $(TAT_BIN)
+
+install: $(XYD_BIN) $(TAT_BIN)
+ $(INSTALL) -c -o bin -g bin -m 0755 $(XYD_BIN) $(EBIN)
+ $(INSTALL) -c -o bin -g bin -m 0755 $(TAT_BIN) $(EBIN)
+ $(INSTALL) -c -o root -g sys -m 0755 ./scripts/imapproxy $(ETC)/init.d
+ ln -s ../init.d/imapproxy /etc/rc2.d/S99imapproxy
+ ln -s ../init.d/imapproxy /etc/rc0.d/K10imapproxy
+ $(INSTALL) -c -o root -g bin -m 0755 ./scripts/imapproxy.conf $(ETC)
+
+
+####
Added: trunk/imap_proxy/README
===================================================================
--- trunk/imap_proxy/README (rev 0)
+++ trunk/imap_proxy/README 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,176 @@
+ Copyright 2002, University of Pittsburgh
+
+
+This directory contains the source distribution of the University of Pittsburgh
+IMAP proxy server.
+
+Send any bugs, questions, comments, patches, kind words, feature requests,
+or hostile words to:
+
+dg...@pi...
+
+For that matter, if you decide to use this software, pop me an email and let me
+know how it works for you.
+
+##############################################################################
+KNOWN ISSUES
+##############################################################################
+
+Currently, this server will only build correctly on Solaris platforms. The
+largest reason is because the md5 routines used for internal storage of
+user passwords is Solaris specific. There are other smaller dependencies,
+though.
+
+Also note that the proxy server only supports LOGIN, not AUTHENTICATE.
+
+
+##############################################################################
+HOW TO BUILD
+##############################################################################
+
+To build the proxy server on a Solaris platform, just run "make" in
+this directory. "make install" will attempt to install the following files:
+
+/usr/local/sbin/in.imapproxyd
+/usr/local/bin/pimpstat
+/etc/init.d/imapproxy
+/etc/rc2.d/S99imapproxy
+/etc/rc0.d/K10imapproxy
+/etc/imapproxy.conf
+
+
+After you successfully build the proxy server, you'll need to edit the
+global configuration file to suit your needs. By default, the proxy
+server looks at /etc/imapproxy.conf as his default configuration file. You
+can change this at runtime by supplying the -f argument to
+/usr/local/sbin/in.imapproxyd.
+
+/usr/local/bin/pimpstat is the Pitt IMap Proxy Statistical tool. It's a little
+curses-based application that you can use to monitor the proxy server. It's
+aware of the same global configuration file as the proxy server, and can also
+be told to look at a different configuration file by supplying it as a
+parameter with the -f argument. Both pimpstat and in.imapproxyd must be using
+the same configuration file, since the stat file that they both rely on is
+set in the configuration file.
+
+
+##############################################################################
+CONFIGURATION OPTIONS
+##############################################################################
+
+server_hostname
+---------------
+This determines which imap server you want to proxy connections to.
+
+cache_size
+----------
+A slightly misleading configuration option. It's really the total number of
+in-core connections that the server can handle, so it will include all of the
+active connections and all of the cached connections. For performance, no
+memory is dynamically allocated within the proxy server once it starts to
+accept connections. That means that all of the IMAP connection structures have
+to be allocated at server startup. This configuration setting allows you to
+control how many of these structures are allocated. The higher you make this
+number, the more memory the server will allocate. Also, since the proxy
+server is multi-threaded it will need to increase the total number of allowed
+file descriptors it can have open. We run with a default setting of 3072
+here. I don't know how big you can make this number before you'd have
+problems with setrlimit().
+
+listen_port
+-----------
+The port that the server binds to and accepts connections on. This is the
+tcp port that IMAP clients will connect to.
+
+cache_expiration_time
+---------------------
+This is the number of seconds that we keep a connection open to the IMAP server
+after a client logs out. Once a client logs out, the in-core IMAP connection
+structure is marked as "cached" instead of "active" and a timestamp is set on
+the structure. Once "cache_expiration_time" seconds have elapsed, this
+connection to the server will be closed and any future logins from the user
+that was connected on this socket will require a new connection to the server.
+
+proc_username
+-------------
+The proxy server will NOT run as root. This is quite simply for security
+reasons. You can specify which user you want the proxy to run as here.
+
+proc_groupname
+--------------
+This is the groupname that the proxy server will run as.
+
+stat_filename
+-------------
+The proxy server opens a file and mmap()s a statistical structure when it
+starts. It keeps some really simple numbers in here. You can use the
+pimpstat application to display these numbers and monitor the usage of the
+proxy server.
+
+protocol_log_filename
+---------------------
+The proxy server allows you to turn on protocol logging on a per-user basis.
+All proxied traffic for one user will be logged to this file, differentiated
+by client or server. This file is opened at server startup, and is held open
+until the server is shut down.
+
+
+##############################################################################
+ADDITIONAL COMMANDS:
+##############################################################################
+
+There are a few additional commands that have been added to allow you to
+administer the proxy server. They're implemented through the same mechanism
+as regular imap protocol commands, so they require you to telnet to your
+proxy server on whatever port you choose to bind to and type them like a
+regular protocol transaction. At our site, we've severely limited access to
+the proxy port such that only our webmail machines and one internal admin
+machine can access it. The proxy server software offers no way to limit the
+usage of these commands by username.
+
+P_NEWLOG
+--------
+Since the protocol log file is held open as long as the server is running,
+it's difficult to clear the logfile. This command was added to take care of
+that for you. It doesn't accept any arguments.
+
+P_DUMPICC
+---------
+The Dump ICC command allows you to display the internal data structures of the
+proxy server. It can tell you how many connections you currently have open,
+what users they're for, and the status of the connections (active or cached).
+Use this sparingly if the proxy server is extremely busy.
+
+P_TRACE
+-------
+This is used to turn on or off protocol logging. If issued without any
+arguments, it will disable protocol logging. If issued with a username
+argument, it will turn on logging for that particular user. Protocol log
+output will show up in the file configured as "protocol_log_filename" in the
+configuration file.
+
+P_RESETCOUNTERS
+---------------
+This allows you to reset the internal counters that pimpstat reports on
+without having to restart the server. These are the counters that are mmap()ed
+to the file configured as "stat_filename" in the configuration file.
+
+
+Happy proxying,
+
+Dave
+
+ _________
+ / |
+ / |
+ / ______|
+ / / ________
+ | | | /
+ | | |_____/
+ | | ______
+ | | | \
+ | | |______\
+ \ \_______
+ \ |
+ \ |
+ \_________|
Added: trunk/imap_proxy/include/common.h
===================================================================
--- trunk/imap_proxy/include/common.h (rev 0)
+++ trunk/imap_proxy/include/common.h 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,74 @@
+/*
+**
+** Copyright (c) 2002 University of Pittsburgh
+**
+** All Rights Reserved
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted,
+** provided that the above copyright notice appears in all copies and that
+** both that copyright notice and this permission notice appear in
+** supporting documentation, and that the name of the University of
+** Pittsburgh not be used in advertising or publicity pertaining to
+** distribution of this software without specific written prior permission.
+**
+** THE UNIVERSITY OF PITTSBURGH DISCLAIMS ALL WARRANTIES WITH REGARD TO
+** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+** FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF PITTSBURGH BE LIABLE FOR
+** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+** RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+** CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**
+**
+** Facility:
+**
+** common.h
+**
+** Abstract:
+**
+** Function declarations for public entry points to common library
+** functions.
+**
+** Authors:
+**
+** Dave McMurtrie (dg...@pi...)
+**
+** RCS:
+**
+** $Source: /afs/pitt.edu/usr12/dgm/work/IMAP_Proxy/include/RCS/common.h,v $
+** $Id: common.h,v 1.2 2002/12/19 21:43:35 dgm Exp $
+**
+** Modification History:
+**
+** $Log: common.h,v $
+** Revision 1.2 2002/12/19 21:43:35 dgm
+** modified parameter list of becomenonroot to support global config.
+**
+** Revision 1.1 2002/08/29 16:31:19 dgm
+** Initial revision
+**
+**
+*/
+
+#ifndef __COMMON_H
+#define __COMMON_H
+
+
+#define HASH_TABLE_SIZE 1024
+
+/*
+ * Function prototypes for public entry points to common Pitt functions.
+ */
+
+/*
+ * Misc. Functions.
+ */
+extern int BecomeNonRoot( void );
+extern unsigned int Hash(char *, unsigned int );
+
+
+#endif /* COMMON_H */
+
+
+
Added: trunk/imap_proxy/include/imapproxy.h
===================================================================
--- trunk/imap_proxy/include/imapproxy.h (rev 0)
+++ trunk/imap_proxy/include/imapproxy.h 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,199 @@
+/*
+**
+** Copyright (c) 2002 University of Pittsburgh
+**
+** All Rights Reserved
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted,
+** provided that the above copyright notice appears in all copies and that
+** both that copyright notice and this permission notice appear in
+** supporting documentation, and that the name of the University of
+** Pittsburgh not be used in advertising or publicity pertaining to
+** distribution of this software without specific written prior permission.
+**
+** THE UNIVERSITY OF PITTSBURGH DISCLAIMS ALL WARRANTIES WITH REGARD TO
+** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+** FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF PITTSBURGH BE LIABLE FOR
+** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+** RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+** CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**
+**
+** Facility:
+**
+** imapproxy.h
+**
+** Abstract:
+**
+** Common definitions and function prototypes for the imap proxy server.
+**
+** Authors:
+**
+** Dave McMurtrie (dg...@pi...)
+**
+** RCS:
+**
+** $Source: /afs/pitt.edu/usr12/dgm/work/IMAP_Proxy/include/RCS/imapproxy.h,v $
+** $Id: imapproxy.h,v 1.4 2002/12/19 21:41:32 dgm Exp $
+**
+** Modification History:
+**
+** $Log: imapproxy.h,v $
+** Revision 1.4 2002/12/19 21:41:32 dgm
+** Added support for global configuration.
+**
+** Revision 1.3 2002/08/30 13:21:42 dgm
+** Added total client logins counter to IMAPCounter struct
+**
+** Revision 1.2 2002/08/29 16:33:46 dgm
+** Added CountTime field to struct IMAPCounter.
+** Removed #define for max number of open file descriptors since
+** we now determine rlimit dynamically instead.
+** Added POLL_TIMEOUT stuff.
+**
+** Revision 1.1 2002/07/03 11:21:12 dgm
+** Initial revision
+**
+**
+*/
+
+
+#ifndef __IMAPPROXY_H
+#define __IMAPPROXY_H
+
+#include <netdb.h>
+
+
+/*
+ * Common definitions
+ */
+#define IMAP_UNTAGGED_OK "* OK " /* untagged OK response */
+#define IMAP_TAGGED_OK "1 OK " /* tagged OK response */
+#define BUFSIZE 1024 /* default buffer size */
+#define MAX_CONN_BACKLOG 5 /* tcp connection backlog */
+#define MAXTAGLEN 256 /* max IMAP tag length */
+#define MAXUSERNAMELEN 64 /* max username length */
+#define MAXPASSWDLEN 64 /* max passwd length */
+#define POLL_TIMEOUT_MINUTES 30 /* Poll timeout in minutes */
+#define POLL_TIMEOUT (POLL_TIMEOUT_MINUTES * 60000)
+#define DEFAULT_CONFIG_FILE "/etc/imapproxy.conf"
+
+
+/*
+ * One IMAPServerDescriptor will be globally allocated such that each thread
+ * can save the time of doing host lookups, service lookups, and filling
+ * in the sockaddr_in struct.
+ */
+struct IMAPServerDescriptor
+{
+ struct hostent host; /* IMAP host entry */
+ struct servent serv; /* IMAP service entry */
+ struct sockaddr_in srv; /* IMAP socket address */
+};
+
+
+/*
+ * IMAPTransactionDescriptors facilitate multi-line buffered reads from
+ * IMAP servers and clients.
+ */
+struct IMAPTransactionDescriptor
+{
+ int sd; /* socket descriptor */
+ char ReadBuf[ BUFSIZE ]; /* Read Buffer */
+ unsigned int BytesInReadBuffer; /* bytes left in read buffer */
+ unsigned int ReadBytesProcessed; /* bytes already processed in read buf */
+ long LiteralBytesRemaining; /* num of bytes left to read as literal */
+ unsigned char NonSyncLiteral; /* rfc2088 alert flag */
+ unsigned char MoreData; /* flag to tell caller "more data" */
+ unsigned char TraceOn; /* trace this transaction? */
+};
+
+
+/*
+ * IMAPConnectionContext structures are used to cache connection info on
+ * a per-user basis.
+ */
+struct IMAPConnectionContext
+{
+ int server_sd; /* server-side socket descriptor */
+ char username[64]; /* username connected on this sd */
+ char hashedpw[16]; /* md5 hash copy of password */
+ unsigned long logouttime; /* time the user logged out last */
+ struct IMAPConnectionContext *next; /* linked list next pointer */
+};
+
+
+/*
+ * One ProxyConfig structure will be used globally to keep track of
+ * configurable options.
+ */
+struct ProxyConfig
+{
+ unsigned int listen_port; /* port we bind to */
+ char *server_hostname; /* server we proxy to */
+ unsigned int server_port; /* port we proxy to */
+ unsigned long cache_size; /* number of cache slots */
+ unsigned long cache_expiration_time; /* cache exp time in seconds */
+ char *proc_username; /* username to run as */
+ char *proc_groupname; /* groupname to run as */
+ char *stat_filename; /* mmap()ed stat filename */
+ char *protocol_log_filename; /* global trace filename */
+};
+
+
+/*
+ * One IMAPCounter structure will be used globally to keep track of
+ * several different things that we want to keep a count of, purely for
+ * diagnostic, or usage tracking purposes.
+ *
+ * IMPORTANT NOTE: No attempt is made to guarantee that these counters
+ * will be completely accurate. No mutex is ever taken out when these
+ * counters are updated. This was done for performance -- these numbers
+ * aren't considered important enough to waste time locking a mutex to
+ * guarantee their accuracy.
+ */
+struct IMAPCounter
+{
+ time_t StartTime;
+ time_t CountTime;
+ unsigned int CurrentClientConnections;
+ unsigned int PeakClientConnections;
+ unsigned int InUseServerConnections;
+ unsigned int PeakInUseServerConnections;
+ unsigned int RetainedServerConnections;
+ unsigned int PeakRetainedServerConnections;
+ unsigned long TotalClientConnectionsAccepted;
+ unsigned long TotalClientLogins;
+ unsigned long TotalServerConnectionsCreated;
+ unsigned long TotalServerConnectionsReused;
+};
+
+
+
+typedef struct IMAPServerDescriptor ISD_Struct;
+typedef struct IMAPTransactionDescriptor ITD_Struct;
+typedef struct IMAPConnectionContext ICC_Struct;
+typedef struct IMAPCounter IMAPCounter_Struct;
+typedef struct ProxyConfig ProxyConfig_Struct;
+
+
+/*
+ * Function prototypes for external entry points.
+ */
+extern int IMAP_Line_Read( ITD_Struct * );
+extern int IMAP_Literal_Read( ITD_Struct * );
+extern void HandleRequest( int );
+extern char *memtok( char *, char *, char ** );
+extern int imparse_isatom( const char * );
+extern int Get_Server_sd( char *, char *, const char * );
+extern void ICC_Logout( char *, int );
+extern void ICC_Recycle( unsigned int );
+extern void ICC_Recycle_Loop( void );
+extern void LockMutex( pthread_mutex_t * );
+extern void UnLockMutex( pthread_mutex_t * );
+extern void SetConfigOptions( char * );
+
+#endif /* __IMAPPROXY_H */
+
Added: trunk/imap_proxy/scripts/imapproxy
===================================================================
--- trunk/imap_proxy/scripts/imapproxy (rev 0)
+++ trunk/imap_proxy/scripts/imapproxy 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,91 @@
+#!/bin/sh
+##
+## Copyright (c) 2002 University of Pittsburgh
+##
+## All Rights Reserved
+##
+## Permission to use, copy, modify, and distribute this software and its
+## documentation for any purpose and without fee is hereby granted,
+## provided that the above copyright notice appears in all copies and that
+## both that copyright notice and this permission notice appear in
+## supporting documentation, and that the name of the University of
+## Pittsburgh not be used in advertising or publicity pertaining to
+## distribution of this software without specific written prior permission.
+##
+## THE UNIVERSITY OF PITTSBURGH DISCLAIMS ALL WARRANTIES WITH REGARD TO
+## THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+## FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF PITTSBURGH BE LIABLE FOR
+## ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+## RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+## CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+## CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+##
+##
+## Facility:
+##
+## imapproxy
+##
+## Abstract:
+##
+## in.imapproxyd startup script
+##
+## Authors:
+##
+## Dave McMurtrie (dg...@pi...)
+##
+## RCS:
+##
+## $Source: /afs/pitt.edu/usr12/dgm/work/IMAP_Proxy/scripts/RCS/imapproxy,v $
+## $Id: imapproxy,v 1.2 2002/12/19 21:48:07 dgm Exp $
+##
+## Modification History:
+##
+## $Log: imapproxy,v $
+## Revision 1.2 2002/12/19 21:48:07 dgm
+## Removed the notion of the startup script reading the config file and
+## passing arguments to the server process on startup.
+##
+## Revision 1.1 2002/07/03 14:02:55 dgm
+## Initial revision
+##
+##
+
+Pgm=`/bin/basename $0`
+
+
+case $1 in
+
+ 'start')
+
+ # make sure the executable exists.
+
+ if [ ! -f /usr/local/sbin/in.imapproxyd ]; then
+ /bin/echo "$Pgm: /usr/local/sbin/in.imapproxyd does not exist. Not starting IMAP proxy server." 1>&2
+ exit 1
+ fi
+
+ /bin/echo "$Pgm: Starting IMAP proxy server." 1>&2
+
+ /usr/local/sbin/in.imapproxyd
+
+ ;;
+
+
+
+ 'stop')
+
+ /bin/echo "$Pgm: Shutting down IMAP proxy server." 1>&2
+
+ pkill -x in.imapproxyd
+
+ ;;
+
+
+ *)
+ /bin/echo "usage: $Pgm {start|stop}" 1>&2
+
+ exit 0
+
+ ;;
+
+esac
Property changes on: trunk/imap_proxy/scripts/imapproxy
___________________________________________________________________
Added: svn:executable
+ *
Added: trunk/imap_proxy/scripts/imapproxy.conf
===================================================================
--- trunk/imap_proxy/scripts/imapproxy.conf (rev 0)
+++ trunk/imap_proxy/scripts/imapproxy.conf 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,84 @@
+## imapproxy.conf
+##
+## This is the global configuration file for the University of Pittsburgh
+## IMAP proxy server.
+##
+
+#
+## server_hostname
+##
+## This setting controls which imap server we proxy our connections to.
+#
+server_hostname your.imap.server.com
+
+
+#
+## cache_size
+##
+## This setting determines how many in-core imap connection structures
+## will be allocated. As such, it determines not only how many cached
+## connections will be allowed, but really the total number of simultaneous
+## connections, cached and active.
+#
+cache_size 3072
+
+
+#
+## listen_port
+##
+## This setting specifies which port the proxy server will bind to and
+## accept incoming connections from.
+#
+listen_port 143
+
+
+#
+## server_port
+##
+## This setting specifies the port that server_hostname is listening on.
+## This is the tcp port that we proxy inbound connections to.
+#
+server_port 143
+
+#
+## cache_expiration_time
+##
+## This setting controls how many seconds an inactive connection will be
+## cached.
+#
+cache_expiration_time 300
+
+
+#
+## proc_username
+##
+## This setting controls which username the imap proxy process will run as.
+## It is not allowed to run as "root".
+#
+proc_username nobody
+
+#
+## proc_groupname
+##
+## This setting controls which groupname the imap proxy process will run as.
+#
+proc_groupname nobody
+
+
+#
+## stat_filename
+##
+## This is the path to the filename that the proxy server mmap()s to
+## write statistical data to. This is the file that pimpstat needs to
+## look at to be able to provide his useful stats.
+#
+stat_filename /var/run/pimpstats
+
+
+#
+## protocol_log_filename
+##
+## protocol logging may only be turned on for one user at a time. All
+## protocol logging data is written to the file specified by this path.
+#
+protocol_log_filename /var/log/imapproxy_protocol.log
Added: trunk/imap_proxy/src/becomenonroot.c
===================================================================
--- trunk/imap_proxy/src/becomenonroot.c (rev 0)
+++ trunk/imap_proxy/src/becomenonroot.c 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,164 @@
+/*
+**
+** Copyright (c) 2002 University of Pittsburgh
+**
+** All Rights Reserved
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted,
+** provided that the above copyright notice appears in all copies and that
+** both that copyright notice and this permission notice appear in
+** supporting documentation, and that the name of the University of
+** Pittsburgh not be used in advertising or publicity pertaining to
+** distribution of this software without specific written prior permission.
+**
+** THE UNIVERSITY OF PITTSBURGH DISCLAIMS ALL WARRANTIES WITH REGARD TO
+** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+** FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF PITTSBURGH BE LIABLE FOR
+** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+** RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+** CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**
+**
+** Facility:
+**
+** becomenonroot.c
+**
+** Abstract:
+**
+** Routine to switch the unix uid of a running process from root to
+** some other non-zero uid.
+**
+** Authors:
+**
+** Dave McMurtrie (dg...@pi...)
+**
+** RCS:
+**
+** $Source: /afs/pitt.edu/usr12/dgm/work/IMAP_Proxy/src/RCS/becomenonroot.c,v $
+** $Id: becomenonroot.c,v 1.2 2002/12/17 14:26:17 dgm Exp $
+**
+** Modification History:
+**
+** $Log: becomenonroot.c,v $
+** Revision 1.2 2002/12/17 14:26:17 dgm
+** Added suport for global configuration structure.
+**
+** Revision 1.1 2002/08/29 16:24:31 dgm
+** Initial revision
+**
+**
+*/
+
+#include <sys/types.h>
+#include <strings.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <syslog.h>
+#include "imapproxy.h"
+
+extern ProxyConfig_Struct PC_Struct;
+
+
+/*++
+ * Function: BecomeNonRoot
+ *
+ * Purpose: If we are running as root, attempt to change that.
+ *
+ * Parameters: nada
+ *
+ * Returns: 0 on success
+ * -1 on failure
+ *
+ * Authors: dgm
+ *
+ * Notes: Relies on global copy of ProxyConfig_Struct "PC_Struct".
+ * Also worth mentioning that instead of just becoming non-root
+ * this function is now also responsible for chown()ing
+ * the global statistics file. I had to choose
+ * between doing a passwd and group lookup twice (and further
+ * cluttering main) or doing the chown here where it
+ * doesn't logically belong. I chose to put it here, but at
+ * least I documented it...
+ *--
+ */
+extern int BecomeNonRoot( void )
+{
+ char *fn = "BecomeNonRoot()";
+ struct passwd *pwent; /* ptr to a passwd file entry */
+ struct group *gp; /* ptr to a group file entry */
+ uid_t newuid; /* uid we want to run as */
+ gid_t newgid; /* gid we want to run as */
+
+ if ((pwent = getpwnam( PC_Struct.proc_username )) == NULL)
+ {
+ syslog(LOG_WARNING, "%s: getpwnam(%s) failed.",
+ fn, PC_Struct.proc_username);
+ return(-1);
+ }
+ else
+ {
+ newuid = pwent->pw_uid;
+ }
+
+ /*
+ * Since the whole purpose here is to not run as root, make sure that
+ * we don't get UID 0 back for username.
+ */
+ if ( newuid == 0 )
+ {
+ syslog( LOG_ERR, "%s: getpwnam returned UID 0 for '%s'.",
+ fn, PC_Struct.proc_username );
+ return(-1);
+ }
+
+ if ((gp = getgrnam( PC_Struct.proc_groupname )) == NULL)
+ {
+ syslog(LOG_WARNING, "%s: getgrnam(%s) failed.",
+ fn, PC_Struct.proc_groupname);
+ return(-1);
+ }
+ else
+ {
+ newgid = gp->gr_gid;
+ }
+
+ /*
+ * The chown() call gets stuck here. I hate it, but
+ * once in a while there are going to be things in life that I hate.
+ */
+ if ( chown( PC_Struct.stat_filename, newuid, newgid ) < 0 )
+ {
+ syslog( LOG_WARNING, "%s: chown() failed to set ownership of file '%s' to '%s:%s': %s", fn, PC_Struct.stat_filename, PC_Struct.proc_username, PC_Struct.proc_groupname, strerror( errno ) );
+ return( -1 );
+ }
+
+
+ /*
+ * Now the whole reason this function exists... setgid and setuid.
+ */
+
+ syslog( LOG_INFO, "%s: Process will run as uid %d (%s) and gid %d (%s).",
+ fn, newuid, PC_Struct.proc_username,
+ newgid, PC_Struct.proc_groupname );
+
+ if ((setgid(newgid)) < 0 )
+ {
+ syslog(LOG_WARNING, "%s: setgid(%d) failed: %s", fn,
+ newgid, strerror(errno));
+ return(-1);
+ }
+
+ if ((setuid(newuid)) < 0 )
+ {
+ syslog(LOG_WARNING,"%s: setuid(%d) failed: %s", fn,
+ newuid, strerror(errno));
+ return(-1);
+ }
+
+ return(0);
+}
Added: trunk/imap_proxy/src/config.c
===================================================================
--- trunk/imap_proxy/src/config.c (rev 0)
+++ trunk/imap_proxy/src/config.c 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,342 @@
+/*
+**
+** Copyright (c) 2002 University of Pittsburgh
+**
+** All Rights Reserved
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted,
+** provided that the above copyright notice appears in all copies and that
+** both that copyright notice and this permission notice appear in
+** supporting documentation, and that the name of the University of
+** Pittsburgh not be used in advertising or publicity pertaining to
+** distribution of this software without specific written prior permission.
+**
+** THE UNIVERSITY OF PITTSBURGH DISCLAIMS ALL WARRANTIES WITH REGARD TO
+** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+** FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF PITTSBURGH BE LIABLE FOR
+** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+** RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+** CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**
+**
+** Facility:
+**
+** config.c
+**
+** Abstract:
+**
+** Routines for parsing a config file and setting global configuration
+** options.
+**
+** Authors:
+**
+** Dave McMurtrie (dg...@pi...)
+**
+** RCS:
+**
+** $Source: /afs/pitt.edu/usr12/dgm/work/IMAP_Proxy/src/RCS/config.c,v $
+** $Id: config.c,v 1.1 2002/12/17 14:26:49 dgm Exp $
+**
+** Modification History:
+**
+** $Log: config.c,v $
+** Revision 1.1 2002/12/17 14:26:49 dgm
+** Initial revision
+**
+**
+*/
+
+
+#define _REENTRANT
+#define MAX_KEYWORD_LEN 128
+
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "common.h"
+#include "imapproxy.h"
+
+
+/*
+ * External globals
+ */
+extern ProxyConfig_Struct PC_Struct;
+
+
+/*
+ * Internal prototypes
+ */
+static void SetStringValue( char *, char **, unsigned int );
+static void SetNumericValue( char *, int *, unsigned int );
+
+
+
+/*
+ * An array of Config_Structs will need to be allocated, one for
+ * every possible keyword/value combination (plus a NULL). Note that
+ * I declare an array of 100, meaning that there's a hard limit of 99
+ * possible config values right now. Currently, there are only 9 in use.
+ */
+struct Config_Struct
+{
+ char Keyword[MAX_KEYWORD_LEN]; /* The configuration keyword */
+ void (*(SetFunction))(); /* ptr to function used to set the value */
+ void *StorageAddress; /* address to store the value */
+};
+
+struct Config_Struct ConfigTable[ 100 ];
+
+/*
+ * Macro to populate the above ConfigTable
+ */
+#define ADD_TO_TABLE( KEYWORD, SETFUNCTION, STA, INDEX ) \
+ strncpy( ConfigTable[ INDEX ].Keyword, KEYWORD, MAX_KEYWORD_LEN -1 ); \
+ ConfigTable[ INDEX ].SetFunction = SETFUNCTION; \
+ ConfigTable[ INDEX ].StorageAddress = STA; \
+ INDEX++;
+
+
+
+
+
+/*++
+ * Function: SetStringValue
+ *
+ * Purpose: Common routine to assign string values in the config
+ * options struct.
+ *
+ * Parameters: ptr to string from config file
+ * ptr to char ptr for dynamically allocated storage for string.
+ * int -- line of config file where the string was read from.
+ *
+ * Returns: nada -- exit()s on errors.
+ *
+ * Authors: dgm
+ *
+ * Notes:
+ *--
+ */
+static void SetStringValue( char *String,
+ char **SavedString,
+ unsigned int linenum )
+{
+ char *fn = "SetStringValue()";
+ unsigned int Size;
+
+ Size = strlen( String ) + 1;
+
+ /*
+ * Do some reasonable bounds checking before we malloc()
+ */
+ if ( ( Size < 1 ) || ( Size > 4096 ) )
+ {
+ syslog( LOG_ERR, "%s: Length of string value at line %d of config file is not within size boundaries -- Exiting.", fn, linenum );
+ exit( 1 );
+ }
+
+ *SavedString = malloc( Size );
+
+ if ( ! *SavedString )
+ {
+ syslog( LOG_ERR, "%s: malloc() failed: %s -- Exiting.", fn,
+ strerror( errno ) );
+ exit( 1 );
+ }
+
+ memcpy( *SavedString, String, Size );
+
+ return;
+}
+
+
+
+
+
+/*++
+ * Function: SetNumericValue
+ *
+ * Purpose: Common routine to convert an ascii string to a numeric value
+ * and set a config value accordingly.
+ *
+ * Parameters: ptr to the string value to convert.
+ * ptr to int. (where to store the converted value)
+ * int -- line of config file where the string was read from.
+ *
+ * Returns: nada -- exit()s on failure.
+ *
+ * Authors: dgm
+ *
+ * Notes:
+ *--
+ */
+static void SetNumericValue( char *StringValue,
+ int *Value,
+ unsigned int linenum )
+{
+ char *fn = "SetNumericValue()";
+
+ /*
+ * Need to generalize this routine. atoi() seems to only set errno
+ * on Solaris, making this very platform specific.
+ */
+ *Value = atoi( (const char *)StringValue );
+
+ if ( ( ! *Value ) &&
+ ( errno == EINVAL ) )
+ {
+ syslog( LOG_ERR, "%s: numeric value specified at line %d
+ of config file is invalid -- Exiting.", fn, linenum );
+ exit( 1 );
+ }
+
+ return;
+}
+
+
+/*++
+ * Function: SetConfigOptions
+ *
+ * Purpose: Set global configuration options by reading and parsing
+ * the configuration file.
+ *
+ * Parameters: char pointer to config filename path.
+ *
+ * Returns: nada. exit()s on any error.
+ *
+ * Authors: dgm
+ *
+ * Notes: Sets values in global ProxyConfig_Struct PC_Struct.
+ *--
+ */
+extern void SetConfigOptions( char *ConfigFile )
+{
+ FILE *FP;
+ char *fn = "SetConfigOptions()";
+ char Buffer[1024];
+ unsigned int LineNumber;
+ unsigned int index;
+ unsigned int i;
+ char *CP;
+ char *Keyword;
+ char *Value;
+
+ index = LineNumber = 0;
+
+ /*
+ * Build our config option table.
+ */
+ ADD_TO_TABLE( "server_hostname", SetStringValue,
+ &PC_Struct.server_hostname, index );
+
+ ADD_TO_TABLE( "listen_port", SetNumericValue,
+ &PC_Struct.listen_port, index );
+
+ ADD_TO_TABLE( "server_port", SetNumericValue,
+ &PC_Struct.server_port, index );
+
+ ADD_TO_TABLE( "cache_size", SetNumericValue,
+ &PC_Struct.cache_size, index );
+
+ ADD_TO_TABLE( "cache_expiration_time", SetNumericValue,
+ &PC_Struct.cache_expiration_time, index );
+
+ ADD_TO_TABLE( "proc_username", SetStringValue,
+ &PC_Struct.proc_username, index );
+
+ ADD_TO_TABLE( "proc_groupname", SetStringValue,
+ &PC_Struct.proc_groupname, index );
+
+ ADD_TO_TABLE( "stat_filename", SetStringValue,
+ &PC_Struct.stat_filename, index );
+
+ ADD_TO_TABLE( "protocol_log_filename", SetStringValue,
+ &PC_Struct.protocol_log_filename, index );
+
+ ConfigTable[index].Keyword[0] = '\0';
+
+ FP = fopen( ConfigFile, "r" );
+
+ if ( !FP )
+ {
+ syslog(LOG_ERR, "%s: Unable to open config file '%s': %s -- Exiting",
+ fn, ConfigFile, strerror( errno ) );
+ exit( 1 );
+ }
+
+ for ( ;; )
+ {
+ if ( !fgets( Buffer, sizeof Buffer, FP ) )
+ break;
+
+ LineNumber++;
+
+ /*
+ * Nullify comments, and CRLFs
+ */
+ CP = strchr( Buffer, '#' );
+ if ( CP ) *CP = 0;
+
+ CP = strchr( Buffer, '\n' );
+ if ( CP ) *CP = 0;
+
+ CP = strchr( Buffer, '\r' );
+ if ( CP ) *CP = 0;
+
+ /*
+ * Any line that started with a comment or CRLF, we'll
+ * skip.
+ */
+ if ( !strlen( Buffer ) )
+ continue;
+
+ CP = strtok( Buffer, " " );
+ if ( !CP )
+ {
+ syslog(LOG_ERR, "%s: parse error reading config file at line %d. Exiting.", fn, LineNumber );
+ exit( 1 );
+ }
+
+ Keyword = CP;
+
+ CP = strtok( NULL, " " );
+
+ if ( !CP )
+ {
+ syslog(LOG_ERR, "%s: parse error reading config file at line %d. Exiting.", fn, LineNumber );
+ exit( 1 );
+ }
+
+ Value = CP;
+
+ for (i = 0; ConfigTable[i].Keyword; i++ )
+ {
+ if ( ! strcasecmp( (const char *)Keyword, ConfigTable[i].Keyword ) )
+ {
+ ( ConfigTable[i].SetFunction )( Value,
+ ConfigTable[i].StorageAddress,
+ LineNumber );
+ break;
+ }
+
+ }
+
+ /*
+ * If we get here and we're at our NULL value at the end of our
+ * keyword array, we cycled through the entire array and never
+ * matched any keyword.
+ */
+ if ( ! ConfigTable[i].Keyword )
+ {
+ syslog( LOG_ERR, "%s: unknown keyword '%s' found at line %d of config file -- Exiting.", fn, Keyword, LineNumber );
+ exit( 1 );
+ }
+
+ }
+
+}
+
+
Added: trunk/imap_proxy/src/hash.c
===================================================================
--- trunk/imap_proxy/src/hash.c (rev 0)
+++ trunk/imap_proxy/src/hash.c 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,103 @@
+/*
+**
+** Copyright (c) 2002 University of Pittsburgh
+**
+** All Rights Reserved
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted,
+** provided that the above copyright notice appears in all copies and that
+** both that copyright notice and this permission notice appear in
+** supporting documentation, and that the name of the University of
+** Pittsburgh not be used in advertising or publicity pertaining to
+** distribution of this software without specific written prior permission.
+**
+** THE UNIVERSITY OF PITTSBURGH DISCLAIMS ALL WARRANTIES WITH REGARD TO
+** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+** FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF PITTSBURGH BE LIABLE FOR
+** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+** RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+** CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**
+**
+** Facility:
+**
+** Hashing routines
+**
+** Abstract:
+**
+** Routines to provide an easy interface to hashing functions.
+**
+** Authors:
+**
+** Ben Carter
+**
+** RCS:
+**
+** $Source: /afs/pitt.edu/usr12/dgm/work/IMAP_Proxy/src/RCS/hash.c,v $
+** $Id: hash.c,v 1.1 2002/08/29 16:27:23 dgm Exp $
+**
+** Modification History:
+**
+** $Log: hash.c,v $
+** Revision 1.1 2002/08/29 16:27:23 dgm
+** Initial revision
+**
+**
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include "common.h"
+
+/*++
+ * Function: Hash
+ *
+ * Purpose: Generate a hash key.
+ *
+ * Parameters: pointer to char -- input key
+ * unsigned int -- maximum length of the input key
+ * unsigned int -- hash table size
+ *
+ * Returns: unsigned int -- hash key
+ *
+ * Authors: bhc
+ *--
+ */
+unsigned int Hash(char *Input_Key, unsigned int Table_Size )
+{
+ unsigned int i;
+ unsigned int Size;
+ unsigned int Longwords;
+ unsigned int *I_Pointer;
+ unsigned int Hash_Value=0;
+ char Hash_Buffer[1024];
+ Size = strlen( Input_Key );
+
+ if ( Size > sizeof Hash_Buffer )
+ {
+ syslog(LOG_ERR, "Hash(): Maximum of %d for '%s' exceeds architectural limit of %d", Size, Input_Key, sizeof Hash_Buffer );
+ exit(1);
+ }
+
+ Longwords = ( ( Size + 3 ) / 4 );
+ memset( Hash_Buffer, 0, Longwords*4 );
+ memcpy( Hash_Buffer, Input_Key, Size );
+ I_Pointer = (unsigned int *) Hash_Buffer;
+
+ for ( i=0; i<Longwords; i++ )
+ {
+ Hash_Value = Hash_Value + *I_Pointer;
+ I_Pointer++;
+ }
+
+ Hash_Value = Hash_Value + Size;
+
+ Hash_Value = Hash_Value % Table_Size;
+
+ return(Hash_Value);
+}
Added: trunk/imap_proxy/src/icc.c
===================================================================
--- trunk/imap_proxy/src/icc.c (rev 0)
+++ trunk/imap_proxy/src/icc.c 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,303 @@
+/*
+**
+** Copyright (c) 2002 University of Pittsburgh
+**
+** All Rights Reserved
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted,
+** provided that the above copyright notice appears in all copies and that
+** both that copyright notice and this permission notice appear in
+** supporting documentation, and that the name of the University of
+** Pittsburgh not be used in advertising or publicity pertaining to
+** distribution of this software without specific written prior permission.
+**
+** THE UNIVERSITY OF PITTSBURGH DISCLAIMS ALL WARRANTIES WITH REGARD TO
+** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+** FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF PITTSBURGH BE LIABLE FOR
+** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+** RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+** CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**
+**
+** Facility:
+**
+** icc.c
+**
+** Abstract:
+**
+** Routines to manipulate IMAP Connection Context structures.
+**
+** Authors:
+**
+** $Author: dgm $
+**
+** RCS:
+**
+** $Source: /afs/pitt.edu/usr12/dgm/work/IMAP_Proxy/src/RCS/icc.c,v $
+** $Id: icc.c,v 1.3 2002/12/17 14:23:12 dgm Exp $
+**
+** Modification History:
+**
+** $Log: icc.c,v $
+** Revision 1.3 2002/12/17 14:23:12 dgm
+** Added support for global configuration structure.
+**
+** Revision 1.2 2002/08/28 15:55:13 dgm
+** replaced all internal logging calls with standard syslog calls.
+**
+** Revision 1.1 2002/07/03 12:06:58 dgm
+** Initial revision
+**
+**
+*/
+
+
+#define _REENTRANT
+
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "common.h"
+#include "imapproxy.h"
+
+/*
+ * External globals
+ */
+extern ICC_Struct *ICC_free;
+extern ICC_Struct *ICC_HashTable[ HASH_TABLE_SIZE ];
+extern pthread_mutex_t mp;
+extern IMAPCounter_Struct *IMAPCount;
+extern ProxyConfig_Struct PC_Struct;
+
+/*
+ * internal prototypes
+ */
+static void _ICC_Recycle( unsigned int );
+
+
+
+/*++
+ * Function: _ICC_Recycle
+ *
+ * Purpose: core logic to implement the ICC_Recycle() & ICC_Recycle_Loop()
+ * functions.
+ *
+ * Parameters: unsigned int -- ICC expiration time
+ *
+ * Returns: nada
+ *
+ * Authors: dgm
+ *--
+ */
+static void _ICC_Recycle( unsigned int Expiration )
+{
+ char *fn = "_ICC_Recycle()";
+ time_t CurrentTime;
+ int rc;
+ unsigned int HashIndex;
+ ICC_Struct *HashEntry;
+ ICC_Struct *Previous;
+
+ CurrentTime = time(0);
+
+ LockMutex( &mp );
+
+ /*
+ * Need to iterate through every single item in our hash table
+ * to decide if we can free it or not.
+ */
+ for ( HashIndex = 0; HashIndex < HASH_TABLE_SIZE; HashIndex++ )
+ {
+
+ Previous = NULL;
+ HashEntry = ICC_HashTable[ HashIndex ];
+
+ while ( HashEntry )
+ {
+ /*
+ * If the last logout time is non-zero, and it's been logged
+ * out for longer than our default expiration time, free it.
+ * Note that this allows for the logouttime to be explicitly
+ * set to 1 (such as in the Get_Server_sd code) if we want to
+ * reap a connection before waiting the normal expiration
+ * cycle.
+ */
+ if ( HashEntry->logouttime &&
+ ( ( CurrentTime - HashEntry->logouttime ) >
+ Expiration ) )
+ {
+ syslog(LOG_INFO, "Expiring server sd [%d]", HashEntry->server_sd);
+ /* Close the server socket. */
+ close( HashEntry->server_sd );
+
+ /*
+ * This was being counted as a "retained" connection. It was
+ * open, but not in use. Now that we're closing it, we have
+ * to decrement the number of retained connections.
+ */
+ IMAPCount->RetainedServerConnections--;
+
+
+ if ( Previous )
+ {
+ Previous->next = HashEntry->next;
+ HashEntry->next = ICC_free;
+ ICC_free = HashEntry;
+ HashEntry = Previous->next;
+ }
+ else
+ {
+ ICC_HashTable[ HashIndex ] = HashEntry->next;
+ HashEntry->next = ICC_free;
+ ICC_free = HashEntry;
+ HashEntry = ICC_HashTable[ HashIndex ];
+ }
+ }
+ else
+ {
+ Previous = HashEntry;
+ HashEntry = HashEntry->next;
+ }
+ }
+ }
+
+ UnLockMutex( &mp );
+}
+
+
+
+/*++
+ * Function: ICC_Recycle
+ *
+ * Purpose: Reclaim dormant ICC structures. This function is intended to
+ * be called any time a free ICC is needed, but none exist. It
+ * can be passed shorter than default expiration durations to try
+ * to free more ICCs if necessary.
+ *
+ * Parameters: unsigned int -- ICC expiration duration
+ *
+ * Returns: nada
+ *
+ * Authors: dgm
+ *--
+ */
+extern void ICC_Recycle( unsigned int Expiration )
+{
+ char *fn = "ICC_Recycle()";
+
+ _ICC_Recycle( Expiration );
+}
+
+
+
+/*++
+ * Function: ICC_Recycle_Loop
+ *
+ * Purpose: Reclaim dormant ICC structures. This function is intended
+ * to be run continuously as a single thread.
+ *
+ * Parameters: nada
+ *
+ * Returns: nada
+ *
+ * Authors: dgm
+ *
+ * Notes: Relies on global copy of ProxyConfig_Struct "PC_Struct" for
+ * expiration time.
+ *--
+ */
+extern void ICC_Recycle_Loop( void )
+{
+ char *fn = "ICC_Recycle_Loop()";
+
+ for( ;; )
+ {
+ sleep( 60 );
+ _ICC_Recycle( PC_Struct.cache_expiration_time );
+ }
+}
+
+
+
+/*++
+ * Function: ICC_Logout
+ *
+ * Purpose: set the last logout time for an IMAP connection context.
+ *
+ * Parameters: char *Username
+ * int server-side socket descriptor
+ *
+ * Returns: nada
+ *
+ * Authors: dgm
+ *--
+ */
+extern void ICC_Logout( char *Username, int sd )
+{
+ char *fn = "ICC_Logout()";
+ unsigned int HashIndex;
+ ICC_Struct *HashEntry = NULL;
+ ICC_Struct *ICC_Active = NULL;
+ int rc;
+
+ IMAPCount->InUseServerConnections--;
+ IMAPCount->RetainedServerConnections++;
+
+ if ( IMAPCount->RetainedServerConnections >
+ IMAPCount->PeakRetainedServerConnections )
+ IMAPCount->PeakRetainedServerConnections = IMAPCount->RetainedServerConnections;
+
+
+ HashIndex = Hash( Username, HASH_TABLE_SIZE );
+
+ LockMutex( &mp );
+
+ for ( HashEntry = ICC_HashTable[ HashIndex ];
+ HashEntry;
+ HashEntry = HashEntry->next )
+ {
+ if ( ( strcmp( Username, HashEntry->username ) == 0 ) &&
+ ( HashEntry->server_sd == sd ) )
+ {
+ ICC_Active = HashEntry;
+ }
+ }
+
+ if ( !ICC_Active )
+ {
+ UnLockMutex( &mp );
+
+ syslog(LOG_WARNING, "%s: Cannot find ICC for '%s' on server sd %d to set logout time.", fn, Username, sd );
+ return;
+ }
+
+ ICC_Active->logouttime = time(0);
+
+ UnLockMutex( &mp );
+
+ syslog(LOG_INFO, "LOGOUT: '%s' from server sd [%d]", Username, sd );
+
+ return;
+}
+
+
+
+/*
+ * _________
+ * / |
+ * / |
+ * / ______|
+ * / / ________
+ * | | | /
+ * | | |_____/
+ * | | ______
+ * | | | \
+ * | | |______\
+ * \ \_______
+ * \ |
+ * \ |
+ * \_________|
+ */
Added: trunk/imap_proxy/src/imapcommon.c
===================================================================
--- trunk/imap_proxy/src/imapcommon.c (rev 0)
+++ trunk/imap_proxy/src/imapcommon.c 2010-07-25 05:01:00 UTC (rev 13984)
@@ -0,0 +1,960 @@
+/*
+**
+** Copyright (c) 2002 University of Pittsburgh
+**
+** All Rights Reserved
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted,
+** provided that the above copyright notice appears in all copies and that
+** both that copyright notice and this permission notice appear in
+** supporting documentation, and that the name of the University of
+** Pittsburgh not be used in advertising or publicity pertaining to
+** distribution of this software without specific written prior permission.
+**
+** THE UNIVERSITY OF PITTSBURGH DISCLAIMS ALL WARRANTIES WITH REGARD TO
+** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+** FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF PITTSBURGH BE LIABLE FOR
+** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+** RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+** CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+**
+**
+** Facility:
+**
+** imapcommon.c
+**
+** Abstract:
+**
+** Routines common to making IMAP server connections and receiving
+** data from an IMAP server or client.
+**
+** Authors:
+**
+** Dave McMurtrie (dg...@pi...)
+**
+** RCS:
+**
+** $Source: /afs/pitt.edu/usr12/dgm/work/IMAP_Proxy/src/RCS/imapcommon.c,v $
+** $Id: imapcommon.c,v 1.5 2002/12/18 14:39:55 dgm Exp $
+**
+** Modification History:
+**
+** $Log: imapcommon.c,v $
+** Revision 1.5 2002/12/18 14:39:55 dgm
+** Fixed bug in for loop for string literal processing.
+**
+** Revision 1.4 2002/12/17 14:22:41 dgm
+** Added support for global configuration structure.
+**
+** Revision 1.3 2002/08/29 20:22:12 dgm
+** Fixed nasty socket descriptor leak.
+**
+** Revision 1.2 2002/08/28 15:57:49 dgm
+** replaced all internal log function calls with standard syslog calls.
+**
+** Revision 1.1 2002/07/03 12:07:26 dgm
+** Initial revision
+**
+**
+*/
+
+
+#define _REENTRANT
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+#include "imapproxy.h"
+#include <string.h>
+#include <errno.h>
+#include <md5.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslog.h>
+
+/*
+ * External globals
+ */
+extern ICC_Struct *ICC_free;
+extern ICC_Struct *ICC_HashTable[ HASH_TABLE_SIZE ];
+extern ISD_Struct ISD;
+extern pthread_mutex_t mp;
+extern pthread_mutex_t trace;
+extern IMAPCounter_Struct *IMAPCount;
+extern ProxyConfig_Struct PC_Struct;
+
+
+/*++
+ * Function: LockMutex
+ *
+ * Purpose: lock a mutex
+ *
+ * Parameters: ptr to the mutex
+ *
+ * Returns: nada -- exits on failure
+ *
+ * Authors: dgm
+ *
+ * Notes:
+ *--
+ */
+extern void LockMutex( pthread_mutex_t *mutex )
+{
+ char *fn = "LockMutex()";
+ int rc;
+
+ rc = pthread_mutex_lock( mutex );
+ if ( rc )
+ {
+ syslog(LOG_ERR, "%s: pthread_mutex_lock() failed [%d]: Exiting.", fn, rc );
+ exit( 1 );
+ }
+ return;
+}
+
+
+/*++
+ * Function: UnLockMutex
+ *
+ * Purpose: unlock a mutex
+ *
+ * Parameters: ptr to the mutex
+ *
+ * Returns: nada -- exits on failure
+ *
+ * Authors: dgm
+ *
+ * Notes:
+ *--
+ */
+extern void UnLockMutex( pthread_mutex_t *mutex )
+{
+ char *fn = "UnLockMutex()";
+ int rc;
+
+ rc = pthread_mutex_unlock( mutex );
+
+ if ( rc )
+ {
+ syslog( LOG_ERR, "%s: pthread_mutex_unlock() failed [%d]: Exiting.", fn, rc );
+ exit( 1 );
+ }
+ return;
+}
+
+
+
+/*++
+ * Function: Get_Server_sd
+ *
+ * Purpose: When a client login attempt is made, fetch a usable server
+ * socket descriptor. This means that either we reuse an
+ * existing sd, or we open a new one. Hide that abstraction from
+ * the caller...
+ *
+ * Parameters: ptr to username string
+ * ptr to password string
+ * const ptr to client hostname or IP string (for logging only)
+ *
+ * Returns: int sd on success
+ * -1 on failure
+ *
+ * Authors: dgm
+ *
+ *--
+ */
+extern int Get_Server_sd( char *Username,
+ char *Password,
+ const char *ClientAddr )
+{
+ char *fn = "Get_Server_sd()";
+ unsigned int HashIndex;
+ ICC_Struct *HashEntry = NULL;
+ char SendBuf[BUFSIZE];
+ unsigned int BufLen = BUFSIZE - 1;
+ char md5pw[16];
+ char *tokenptr;
+ char *endptr;
+ char *last;
+ ICC_Struct *ICC_Active;
+ ICC_Struct *ICC_tptr;
+ ITD_Struct Server;
+ int rc;
+ unsigned int Expiration;
+
+ Expiration = PC_Struct.cache_expiration_time;
+ memset( &Server, 0, sizeof Server );
+
+ /* need to md5 the passwd regardless, so do that now */
+ md5_calc( md5pw, Password, strlen( Password ) );
+
+ /* see if we have a reusable connection available */
+ ICC_Active = NULL;
+ HashIndex = Hash( Username, HASH_TABLE_SIZE );
+
+ LockMutex( &mp );
+
+ /*
+ * Now we just iterate through the linked list at this hash index until
+ * we either find the string we're looking for or we find a NULL.
+ */
+ for ( HashEntry = ICC_HashTable[ HashIndex ];
+ HashEntry;
+ HashEntry = HashEntry->next )
+ {
+ if ( ( strcmp( Username, HashEntry->username ) == 0 ) &&
+ ( HashEntry->logouttime > 1 ) )
+ {
+ ICC_Active = HashEntry;
+ /*
+ * we found this username in our hash table. Need to know if
+ * the password matches.
+ */
+ if ( memcmp( md5pw, ICC_Active->hashedpw, sizeof md5pw ) )
+ {
+ /* the passwords don't match. Shake this guy. */
+ UnLockMutex( &mp );
+ syslog(LOG_INFO, "LOGIN: '%s' (%s) failed: password incorrect", Username, ClientAddr );
+ return( -1 );
+ }
+
+ /*
+ * We found a matching password on an inactive server socket. We
+ * can use this guy. Before we release the mutex, set the
+ * logouttime such that we mark this connection as "active" again.
+ */
+ ICC_Active->logouttime = 0;
+
+ /*
+ * The fact that we have this stored in a table as an open server
+ * socket doesn't really mean that it's open. The server could've
+ * closed it on us.
+ * We need a speedy way to make sure this is still open.
+ * We'll set the fd to non-blocking and try to read from it. If we
+ * get a zero back, the connection is closed. If we get
+ * EWOULDBLOCK (or some data) we know it's still open. If we do
+ * read data, make sure we read all the data so we "drain" any
+ * puss that may be left on this socket.
+ */
+ fcntl( ICC_Active->server_sd, F_SETFL,
+ fcntl( ICC_Active->server_sd, F_GETFL, 0) | O_NONBLOCK );
+
+ while ( ( rc = recv( ICC_Active->server_sd, Server.ReadBuf,
+ sizeof Server.ReadBuf, 0 ) ) > 0 );
+
+ if ( !rc )
+ {
+ syslog(LOG_NOTICE, "%s: Unable to reuse server sd [%d] for user '%s' (%s). Connection closed by server.", fn, ICC_Active->server_sd, Username, ClientAddr );
+ ICC_Active->logouttime = 1;
+ continue;
+ }
+
+ if ( errno != EWOULDBLOCK )
+ {
+ syslog(LOG_NOTICE, "%s: Unable to reuse server sd [%d] for user '%s' (%s). recv() error: %s", fn, ICC_Active->server_sd, Username, ClientAddr, strerror( errno ) );
+ ICC_Active->logouttime = 1;
+ continue;
+ }
+
+
+ fcntl( ICC_Active->server_sd, F_SETFL,
+ fcntl( ICC_Active->server_sd, F_GETFL, 0) & ~O_NONBLOCK );
+
+
+ /* now release the mutex and return the sd to the caller */
+ UnLockMutex( &mp );
+
+ /*
+ * We're reusing an existing server socket. There are a few
+ * counters we have to deal with.
+ */
+ IMAPCount->RetainedServerConnections--;
+ IMAPCount->InUseServerConnections++;
+ IMAPCount->TotalServerConnectionsReused++;
+
+ if ( IMAPCount->InUseServerConnections >
+ IMAPCount->PeakInUseServerConnections )
+ IMAPCount->PeakInUseServerConnections = IMAPCount->InUseServerConnections;
+
+ syslog(LOG_INFO, "LOGIN: '%s' (%s) on existing sd [%d]", Username, ClientAddr, ICC_Active->server_sd );
+ return( ICC_Active->server_sd );
+ }
+ }
+
+ UnLockMutex( &mp );
+
+ /*
+ * We don't have an active connection for this user.
+ * Open a connection to the IMAP server so we can attempt to login
+ */
+ Server.sd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
+ if ( Server.sd == -1 )
+ {
+ syslog(LOG_INFO, "LOGIN: '%s' (%s) failed: Unable to open server socket: %s",
+ Username, ClientAddr, strerror( errno ) );
+ return( -1 );
+ }
+
+ if ( connect( Server.sd, (struct sockaddr *)&ISD.srv,
+ sizeof(ISD.srv) ) == -1 )
+ {
+ syslog(LOG_INFO, "LOGIN: '%s' (%s) failed: Unable to connect to IMAP server: %s", Username, ClientAddr, strerror( errno ) );
+ close( Server.sd );
+ return( -1 );
+ }
+
+
+ /* Read & throw away the banner line from the server */
+
+ if ( IMAP_Line_Read( &Server ) == -1 )
+ {
+ syslog(LOG_INFO, "LOGIN: '%s' (%s) failed: No banner line received from IMAP server",
+ Username, ClientAddr );
+ close( Server.sd );
+ return( -1 );
+ }
+
+ /*
+ * Send the login command off to the IMAP server.
+ */
+ snprintf( SendBuf, BufLen, "A0001 LOGIN %s %s\r\n",
+ Username, Password );
+
+ if ( send( Server.sd, SendBuf, strlen(SendBuf), 0 ) == -1 )
+ {
+ syslog(LOG_INFO, "LOGIN: '%s' (%s) failed: send() failed attempting to send LOGIN command to IMAP server: %s", Username, ClientAddr, strerror( errno ) );
+ close( Server.sd );
+ return( -1 );
+ }
+
+ /*
+ * Read the server response
+ */
+ if ( ( rc = IMAP_Line_Read( &Server ) ) == -1 )
+ {
+ syslog(LOG_INFO, "LOGIN: '%s' (%s) failed: No response from IMAP server after sending LOGIN command", Username, ClientAddr );
+ close( Server.sd );
+ return( -1 );
+ }
+
+ ...
[truncated message content] |