popとimap

# apt-get install courier-pop-ssl courier-imap-ssl
でcourier-pop(-ssl)、courier-imap(-ssl)がインストールされます。 そのままではldapアカウントはログイン対象になりませんので、
# vi /etc/pam.d/pop および imap
auth     sufficient pam_ldap.so
account  sufficient pam_ldap.so
password sufficient pam_ldap.so

auth     required   pam_unix.so nullok use_first_pass
account  required   pam_unix.so
password required   pam_unix.so try_first_pass
session  required   pam_unix.so
とすればpam経由でldapアカウントにログインできます。 pam経由で認証するので、この使い方においては courier-ldapを導入する必要はありません。 なお、pop-ssl、imap-sslは外部に公開できますが、 imapでないsslはパスワードに平文が流れるので外部に公開しないようにします。 popも外部に公開しない方がいいのですが、 sslやpptpをサポートしないクライアントのために、 APOPを追加してパスワードを隠匿するようにします。

APOPの追加

slapdはAPOP認証対応に改造しておいてください。

% apt-get source courier-pop      Courierメールサーバ全部が入ります
% cd courier-0.37.3
% vi imap/pop3login.c
...
int main(int argc, char **argv)
{
char    *user=0;
char    *p;
char    buf[BUFSIZ];
int     c;
const   char *ip=getenv("TCPREMOTEIP");
unsigned char cred[BUFSIZ+8];
const char b64[]=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
...
        if (authmoduser(argc, argv, 60, 5))
        {
                fprintf(stderr, "INFO: Connection, ip=[%s]\n", ip);
                // printf("+OK Hello there.\r\n");
                sprintf(buf, "MYSECRET%d%d", getpid(), time(0));
                md5_digest(buf, strlen(buf), cred+17);
                cred[16]= '<';
                for(c= 17; c<17+16; c++) cred[c]= b64[cred[c]&0x3f];
                p= getenv("TCPLOCALIP");
                if(p==0) p= "";
                snprintf(cred+17+16, sizeof(cred)-17-16, "@%s>", p);
                cred[sizeof(cred)-1]= 0;
                printf("+OK Hello there. %s\r\n", cred+16);
        }
...
                        } else if (strcmp(p, "PASS") == 0)
                        {
                                p=strtok(0, "\t\r");
                                if(getenv("POP3NOPLAIN")&&getenv("POP3NOPLAIN")[0]) p= 0;
                                if (!user || p == 0)
                                {
                                        printf("-ERR USER/PASS required.\r\n");
                                        fflush(stdout);
                                        continue;
                                }

                                authmod_login(argc-1, argv+1, "pop3", user, p);
                        } else if (strcmp(p, "APOP") == 0) {
                                char *pass;
                                int i;
                                p=strtok(0, " \t\r");
                                if(p==0) {
                                        printf("-ERR user/hash required.\r\n");
                                        fflush(stdout);
                                        continue;
                                }
                                if(user) free(user);
                                if((user= malloc(strlen(p)+1))==0) {
                                        printf("-ERR Server out of memory, aborting connection.\r\n");
                                        fflush(stdout);
                                        perror("malloc");
                                        exit(1);
                                }
                                strcpy(user, p);
                                p= strtok(0, "\t\r");
                                if(p) {
                                        for(i= 0; i<32; i++) {
                                                c= p[i];
                                                if(!(c>='0'&&c<='9'||c>='A'&&c<='F'
                                                ||c>='a'&&c<='f')) { p= 0; break; }
                                        }
                                }
                                if(p==0) {
                                        printf("-ERR user/hash required.\r\n");
                                        fflush(stdout);
                                        continue;
                                }
                                for(i= 0; i<16; i++) {
                                        sscanf(p+i*2, "%2x", &c);
                                        cred[i]= c;
                                }
                                c= strlen(cred+16)+16;
                                if((pass= malloc(6+(c+2)/3*4+1))==0) {
                                        printf("-ERR Server out of memory, aborting connection.\r\n");
                                        fflush(stdout);
                                        perror("malloc");
                                        exit(1);
                                }
                                strcpy(pass, "{APOP}");
                                p= pass+6;
                                for(i= 0; i<c; i+=3) {
                                        int e0, e1, e2;
                                        e0= cred[i];
                                        e1= i+1<c?cred[i+1]:0;
                                        e2= i+2<c?cred[i+2]:0;
                                        *p++= b64[e0>>2];
                                        *p++= b64[e0<<4&0x30|e1>>4];
                                        *p++= i+1<c?b64[e1<<2&0x3c|e2>>6]:'=';
                                        *p++= i+2<c?b64[e2&0x3f]:'=';
                                }
                                *p= 0;
                                authmod_login(argc-1, argv+1, "pop3", user, pass);
                                free(pass);
                        }
...
% vi imap/pop3dcapa.c
...
        printf("TOP\r\nUSER\r\nAPOP\r\nLOGIN-DELAY 10\r\nPIPELINING\r\nUIDL\r\nIMPLEMENTATION Courier Mail Server\r\n.\r\n");
...
修正はこれだけです。MYSECRETはプロセスIDを推察されないためなのでそのままでもまあいいです。コンパイルしてインストールします。
# dpkg-buildpackage
(この時に出るコンパイルに必要なパッケージ群はapt-get installで取ってきます。)
# cd ..
# dpkg -i courier-pop_0.37.3-xxx.deb
入れ替えるのは/usr/lib/courier/courier/courierpop3loginだけですので、
% debian/rules build
# /etc/init.d/courier-pop stop
# /etc/init.d/courier-pop-ssl stop
# cd imap
# strip pop3login; cp pop3login /usr/lib/courier/courier/courierpop3login
# /etc/init.d/courier-pop start
# /etc/init.d/courier-pop-ssl start
でもかまいません。 いずれにせよapt-get upgradeされないようにhold-stateにしておくか、 upgradeかかったら再コピーすることを忘れずに。

サイト内部のみ平文ログインを許可

この改造で、環境変数POP3NOPLAINが空文字以外に設定されていると、 平文ログインを受け付けないようになります。 これを利用して、couriertcpdの-accessオプションと組み合わせることにより、 サイト外部からのログインはapopしか許可せずに、 サイト内部からは通常の平文ログインを許可するようにできます。 (sslの場合は外部からでも平文ログインを許可しておいて安全です。)

# cd /etc/courier
# vi pop3d
...
POP3AUTH=""     AUTH使うPOPクライアントは少ないですが、LOGINは書かないようにします
...
TCPDOPTS="-nodnslookup -noidentlookup -access=/etc/courier/pop3daccess.dat"
...
# vi pop3d-ssl
...  pop3dでの設定をオーバライドし、平文ログインを許可します
TCPDOPTS="-nodnslookup -noidentlookup"
...
# vi pop3daccess
127.0.0.1       allow,POP3NOPLAIN  許可するものを空文字に設定します
10      allow,POP3NOPLAIN          IPアドレスとの間はタブ文字1つです
192.168 allow,POP3NOPLAIN
172.16  allow,POP3NOPLAIN
...
172.31  allow,POP3NOPLAIN
*       allow,POP3NOPLAIN=1        許可しないものは何か設定します
# makedat -src=pop3daccess -tmp=pop3daccess.tmp -file=pop3daccess.dat
# /etc/init.d/courier-pop restart
なお、/etc/courier/pop3daccessを書き換えたらmakedatの実行および popデーモンの再起動が必要です。