山梨大学総合情報処理センターの統合メールサーバ構築において、
メールアカウントをローカルに持たずに、LDAPアカウントを参照して機能するメールシステムを
構築した。MTAであるqmail、マルチドメイン対応アカウント管理ツールであるvpopmail、
LDAP対応imapサーバのcouier-imapのそれぞれ独自のLDAPスキーマおよびLDAP対応システムを
連携・統合するコード修正を行ない、実機にて動作確認とシステムの検証を行なった。
本研究報告ではこのシステム構築において、LDAPメールサーバとしての決定的ソリューションをめざすべく
作成した修正パッチと構築の概略手順を提示しながら、そのポイントおよび構築結果について簡単に述べる。
キーワード: qmail-ldap, vpopmail, tcpserver, daemontools, squirrelmail, qmailadmin, ezmlm
LDAPが世間に登場してから久しいが、実際にLDAPをフル活用した事例はごく少数で、
ドキュメントについても実験的な事例は多く見かけるが、実践的なものはあまり
見受けられない。残念ながら枯れた技術としてLDAPが広く浸透するのは、
もう少し先のように思われる。
メールシステムについても同様で、メールシステムこそLDAPでユーザ管理するに最適な
システムであると思われるが、またまだ広く活用されていないのが現状のようだ。
メールシステムと言えば、しばらく前からポストsendmailとして注目されているのが
qmailである。sendmailと比較したqmailの利点や弱点については、
改めてここで述べるほどではないが、残念ながらqmail本体にはLDAP対応コードは
入っていない。
しかしながら、qmail-ldapと呼ばれるパッチが、Andre Oppermann氏
(webpage: http://www.nrg4u.com/ )により公開され、
現在も大変意欲的にバージョンアップがされ、最短で月1回ペースで公開更新
がされている。
ただし、sendmailやPostfixは本体自身でLDAP対応がされており、これだけでは、
無理にqmail-ldapを選択する必要はないのであるが、qmailには、
仮想メールアカウント・マルチドメイン対応の決定的とも言えるメール管理システム
vpopmailが存在し、また、vpopmailには、Web経由でアカウント管理から
メーリングリスト管理まで簡単に可能なqmailadminパッケージも存在する。
vpopmailは標準でpop認証などをLDAPで行なうことができるが、残念ながら
vpopmailで定義されるLDAPスキーマと、qmail-ldapが要求するそれとが
統一されておらず、また、imapサービスでよく利用されるcourier-imapも
またこれらと独立した設計になっているため、スキーマを単純に共有し、
それぞれを協調して動作させることが現時点では困難になっている。
そこで、本研究では、これらのソフトウェアによるLDAP対応コードを協調させ、
準決定的なLDAP対応メールシステムを目指すべくその第一歩として、
必要なコードを修正した追加パッチの作成および実機での動作確認をし、
その構築手順をまとめることを目標とした。
加えて、追加で必要になりそうな POP beore SMTP や SPAM対策など、
拡張機能と言える部分もできるだけ網羅した標準的・決定的といえる
メールシステムをも視野に入れ、進めることにする。
本研究報告では、ソースに付属しているドキュメントや他のWebページに
よく書かれているインストール手順のような自明な説明は本研究報告では割愛し、
そのポインタのみ示すこととする。
今回のメールサーバ構築に用いる主なソフトウェアの構成は図1のようになっている。 図中の各レイヤは依存関係を示しており、上位のソフトウェアが下のソフトウェア/概念 を利用しているか依存していることを示す。
図1:LDAPメールシステム全体構成図
daemontoolは文字通り、unixのサービスであるdaemonを管理するためのツール群である。
稀にdaemonが何らかの原因で落ちて(=異常終了して)しまい、サービスが止まってしまう
事があるが、daemontoolを利用すると、管理中のdaemonを監視していて、
daemonが落ちた場合でも自動で起動しなおしてくれる。
その他の機能としては、サービスの制御、ログの収集および環境変数・資源制限が可能だ。
作者はqmailの作者でもあるD. J. Bernstein氏である。
% gtar -xvf ../tarball/daemontools-0.70.tar.gz % cd daemontools-0.70 % make # make setup check
----- src/daemontools-0.76/daemontools-0.76-install.sh : --------- 1 | #!/bin/sh 2 | install_dir=/usr/local/bin 3 | for file in command/* ; do 4 | if ( file ${file} | grep -i 'shell script' ) ; then 5 | install -o root -g 0 -m 0755 ${file} ${install_dir} 6 | else 7 | install -o root -g 0 -m 0755 -s ${file} ${install_dir} 8 | fi 9 | done 10 | echo "done."
----- /usr/local/bin/svscanboot : ----------------------------------- 1 | #!/bin/sh 2 | # WARNING: This file was auto-generated. Do not edit! 3 | PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin 4 | exec </dev/null 5 | exec >/dev/null 6 | exec 2>/dev/null 7 | /usr/local/bin/svc -dx /var/daemontools/* /var/daemontools/*/log 8 | env - PATH=$PATH svscan /var/daemontools 2>&1 | ¥ 9 | env - PATH=$PATH readproctitle service errors: ................................................. 10 | ................................................................................................ 11 | ................................................................................................ 12 | ................................................................................................ 13 | ...............................................................
# daemontools: SV:123456:respawn:/usr/local/bin/svscanboot
# daemontools: SV:123456:respawn:/usr/local/bin/svscanboot </dev/null
# kill -HUP 1
外部との通信を行なうdaemonなどは、特定のTCP/UDPポートで待ち構えるために、 通常は inetd に頼るかまたは、すべて自前でソケットを作成して必要な通信処理をする。 IPアドレスによるアクセス制限をしたり、ログを特定のファイルに書き出したり 大体同じ処理を重複してしていることになる。そこで、この部分を分離独立させて 多くのサービスで共通して利用できるようにしたのが ucspi-tcp(tcpserver)である。
一般的にあまり知られていないようだが、pop3やimap4をSSL/TLS化したい場合、 いちばん簡潔で有効なのが、tcpserverにSSL/TLS対応パッチを適用する方法である。
% tar -xvzf ../tarball/ucspi-tcp-0.88.tar.gz % cd ucspi-tcp-0.88 % zcat ucspi-tcp-ssl-20020705.patch.gz | patch % make # make setup check # mkdir /etc/tcpserver /// ←アクセス制限定義ファイルDir
# nec, ldap2.yamanashi.ac.jp, cis, yamanashi-u dn: uid=nec, ou=ldap2.yamanashi.ac.jp,dc=cis,dc=yamanashi-u uid: nec userPassword:: e01ENX0kMSRXTkczaCR6bVp5OW9NWnRqV096YUxlaGVkdkgu /// パスワード例: 'passwd' qmailUID: 89 /// vpopmailのUID(固定) qmailGID: 0 /// 0で固定 qmaildomain: nec /// qmailadmin が gecosフィールドとして使用 mailMessageStore: /home/vpopmail/domains/ldap2.yamanashi.ac.jp/nec mailQuotaSize: NOQUOTA /// メールスプールサイズquota(qmail-ldap-20030901以降) mailQuotaCount: NOQUOTA /// メール数quota(qmail-ldap-20030901以降) clearPassword: passwd /// パスワード例: 'passwd' objectClass: qmailUser mail: nec@ldap2.yamanashi.ac.jp
----- /etc/openldap/slapd.conf : ------------------------------------ 1 | # $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.8.8.7 2001/09/27 20:00:31 kurt Exp $ 2 | # 3 | # See slapd.conf(5) for details on configuration options. 4 | # This file should NOT be world readable. 5 | # (中略) 16 | include /etc/openldap/qmail-vpopmail.schema 17 | schemacheck off (中略) 75 | suffix "dc=cis,dc=yamanashi-u" 76 | rootdn "cn=Manager,dc=cis,dc=yamanashi-u" (中略) 78 | # Cleartext passwords, especially for the rootdn, should 79 | # be avoided. See slappasswd(8) and slapd.conf(5) for details. 80 | # Use of strong authentication encouraged. 81 | rootpw passwd // パスワード例: 'passwd' (中略) 88 | index objectClass,uid,uidNumber,gidNumber,memberUid eq 89 | index cn,mail,surname,givenname eq,subinitial (中略) 97 | access to dn="(.*,)?dc=cis,dc=yamanashi-u" 98 | by dn="cn=Manager,dc=cis,dc=yamanashi-u" write 99 | by self write 100 | by * read 101 | 102 | access to attribute=userPassword 103 | by self write 104 | by dn="cn=Manager,dc=cis,dc=yamanashi-u" write 105 | by anonymous auth 106 | by * none 107 | 108 | access to attribute=clearPassword 109 | by self write 110 | by dn="cn=Manager,dc=cis,dc=yamanashi-u" write 111 | by anonymous auth 112 | by * none 113 | 114 | access to * 115 | by dn="cn=Manager,dc=cis,dc=yamanashi-u" write 116 | by self write 117 | by * read ----- /etc/openldap/qmail-vpopmail.schema : ------------------------- 1 | attributetype ( 1.3.6.1.4.1.8868.3.1.2 2 | NAME 'qmailGID' 3 | DESC 'qmail group id' 4 | EQUALITY caseIgnoreIA5Match 5 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{100} 6 | SINGLE-VALUE ) 7 | 8 | attributetype ( 1.3.6.1.4.1.8868.3.1.3 9 | NAME 'qmailUID' 10 | DESC 'qmail userid' 11 | EQUALITY caseIgnoreIA5Match 12 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{100} 13 | SINGLE-VALUE ) 14 | 15 | attributetype ( 1.3.6.1.4.1.8868.3.1.4 16 | NAME 'qmaildomain' 17 | DESC 'qmail Domain' 18 | EQUALITY octetStringMatch 19 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{100} 20 | SINGLE-VALUE ) 21 | 22 | attributetype ( 1.3.6.1.4.1.8868.3.1.5 23 | NAME 'mailQuotaSize' 24 | DESC 'The size of space the user can have until further messages get bounced.' 25 | EQUALITY integerMatch 26 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{100} 27 | SINGLE-VALUE ) 28 | 29 | attributetype ( 1.3.6.1.4.1.8868.3.1.6 30 | NAME 'mailQuotaiCount' 31 | DESC 'The number of messages the user can have until further messages get bounced.' 32 | EQUALITY integerMatch 33 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{100} 34 | SINGLE-VALUE ) 35 | 36 | attributetype ( 1.3.6.1.4.1.8868.3.1.7 37 | NAME 'mailMessageStore' 38 | DESC 'qmail Store' 39 | EQUALITY caseIgnoreIA5Match 40 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{100} 41 | SINGLE-VALUE ) 42 | 43 | attributetype ( 1.3.6.1.4.1.8868.3.1.8 44 | NAME 'clearPassword' 45 | DESC 'qmail clearpassword for apop' 46 | EQUALITY octetStringMatch 47 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{100} 48 | SINGLE-VALUE ) 49 | 50 | objectclass ( 1.3.6.1.4.1.8868.3.1 51 | NAME 'qmailUser' 52 | DESC 'qmail local mail recipient' 53 | SUP ( top $ person $ organizationalPerson ) 54 | MAY ( qmailGID $ qmailUID $ qmaildomain $ 55 | mailQuotaSize $mailQuotaiCount $ 56 | mailMessageStore $ name $ sn $ cn $ clearPassword) )
以下のようにユーザおよびグループを追加する。UID,GIDは重要である。 ここではqmailの.qmail-*ファイルとvpopmailの連携を密にするため、 (あまり薦められる方法ではないが、) aliasユーザとvpopmailユーザを同一UIDにしている。:
----- /etc/passwd : ------------------------------------------------- 37 | alias:x:89:81::/var/qmail:/bin/true 38 | qmaild:x:82:81::/var/qmail:/bin/true 39 | qmaill:x:83:81::/var/qmail:/bin/true 40 | qmailp:x:84:81::/var/qmail:/bin/true 41 | qmailq:x:85:82::/var/qmail:/bin/true 42 | qmailr:x:86:82::/var/qmail:/bin/true 43 | qmails:x:87:82::/var/qmail:/bin/true 44 | vpopmail:x:89:89::/home/vpopmail:/bin/bash ----- /etc/group : -------------------------------------------------- 43 | nofiles:x:81: 44 | qmail:x:82: 45 | vchkpw:x:89:alias
ここから、いよいよqmail+qmail-ldapのコンパイルとインストールとなる。
*** qmail-1.03-necpatch/qmail-ldap.h.ORIG Sat Mar 13 09:11:36 2004 --- qmail-1.03-necpatch/qmail-ldap.h Sat Mar 13 11:01:40 2004 *************** *** 20,30 **** #define REPLY_CTE "8bit¥n" /* the maximum and minimum uid allowed */ ! #define UID_MIN 100 #define UID_MAX 65535 /* the maximum and minimum gid allowed */ ! #define GID_MIN 100 #define GID_MAX 65535 /* if the sanitycheck function should be less restricted for --- 20,30 ---- #define REPLY_CTE "8bit¥n" /* the maximum and minimum uid allowed */ ! #define UID_MIN 89 /*100*/ #define UID_MAX 65535 /* the maximum and minimum gid allowed */ ! #define GID_MIN 0 /*100*/ #define GID_MAX 65535 /* if the sanitycheck function should be less restricted for *** qmail-1.03-necpatch/qmail-lspawn.c.ORIG Sat Mar 13 09:11:36 2004 --- qmail-1.03-necpatch/qmail-lspawn.c Sat Mar 13 10:59:18 2004 *************** *** 752,758 **** * This is the standart qmail lookup funktion. */ logit(4, "LDAP lookup failed, using local db¥n"); ! nughde_get(r); } else { /* the alias-user handling for LDAP only mode */ struct passwd *pw; --- 752,771 ---- * This is the standart qmail lookup funktion. */ logit(4, "LDAP lookup failed, using local db¥n"); ! ! { /* necpatch20040303: rr := {domain}-{userid} */ ! ! stralloc rr = {0}; ! if (!stralloc_copys(&rr, &r[at+1])) _exit(QLX_NOMEM); ! if (!stralloc_cats(&rr, "-")) _exit(QLX_NOMEM); ! if (!stralloc_cats(&rr, r)) _exit(QLX_NOMEM); ! if (!stralloc_0(&rr)) _exit(QLX_NOMEM); ! /* ! logit(1, "nec-debug: rr.s=%s(len=%d), s=%s, r=%s, r[at]=%s¥n", ! rr.s, rr.len, s, r, r+at+1); ! */ ! nughde_get(rr.s); ! } } else { /* the alias-user handling for LDAP only mode */ struct passwd *pw;
% tar -xvzf ../tar_ball/qmail-1.03.tar.gz % cd qmail-1.03 % patch -p1 < ../tar_ball/qmail-ldap-1.03-20030301.patch % patch -p1 < ../tar_ball/qmail-date-localtime.patch % make % su # make setup check
----- src/vpopmail-5.4.0-necpatch.patch : --------------------------- 1 | diff -c vpopmail-5.4.0-org/vldap.c vpopmail-5.4.0/vldap.c 2 | *** vpopmail-5.4.0-org/vldap.c Thu Jan 8 01:06:16 2004 3 | --- vpopmail-5.4.0/vldap.c Fri Feb 6 15:57:40 2004 4 | *************** 5 | *** 38,49 **** 6 | LDAPMessage *glm = NULL; 7 | 8 | #ifdef CLEAR_PASS 9 | ! # define NUM_LDAP_FIELDS 9 10 | #else 11 | ! # define NUM_LDAP_FIELDS 8 12 | #endif 13 | 14 | ! char *ldap_fields[NUM_LDAP_FIELDS] = { 15 | "uid", /* 0 pw_name */ 16 | "userPassword", /* 1 pw_passwd */ 17 | "qmailUID", /* 2 pw_uid */ 18 | --- 38,51 ---- 19 | LDAPMessage *glm = NULL; 20 | 21 | #ifdef CLEAR_PASS 22 | ! # define NUM_LDAP_FIELDS 10 23 | ! # define NUM_LDAP_FIELDSW 17 24 | #else 25 | ! # define NUM_LDAP_FIELDS 9 26 | ! # define NUM_LDAP_FIELDSW 16 27 | #endif 28 | 29 | ! char *ldap_fields[NUM_LDAP_FIELDSW] = { 30 | "uid", /* 0 pw_name */ 31 | "userPassword", /* 1 pw_passwd */ 32 | "qmailUID", /* 2 pw_uid */ 33 | *************** 34 | *** 57,63 **** 35 | --- 59,152 ---- 36 | "clearPassword", /* 7 pw_clear_passwd */ 37 | "objectclass" /* 8 ldap */ 38 | #endif 39 | + "mail", /* 9 mail-address */ 40 | + 41 | + "cn", /* 10 cn */ 42 | + "sn", /* 11 sn */ 43 | + "objectclass", /* 12 */ 44 | + "objectclass", /* 13 */ 45 | + "objectclass", /* 14 */ 46 | + "objectclass", /* 15 */ 47 | + "objectclass", /* 16 */ 48 | }; 49 | + /*------------------------------------------------------------*/ 50 | + /* 51 | + * vpopmail-ldap configuration file: 52 | + * 20031022: vldap.c implement by k-sasamori@elsd.mt.nec.co.jp 53 | + * 54 | + * configfile path= /home/vpopmail/etc/ldapconfig 55 | + */ 56 | + 57 | + #define VLDAP_DEBUG 0 58 | + 59 | + char *getconfigparam(char *name) 60 | + { 61 | + static int init = 0; 62 | + char sbuf[MAX_BUFF], tmpbuf[MAX_BUFF]; 63 | + struct param_list { char *n; char *v; }; 64 | + 65 | + #define PARAM_LISTS 5 66 | + #define PARAM_NAME_MAXLEN 32 67 | + static struct param_list param[PARAM_LISTS] = { 68 | + { "VLDAP_SERVER", "127.0.0.1" }, 69 | + { "VLDAP_PORT", "389" }, 70 | + { "VLDAP_USER", NULL }, 71 | + { "VLDAP_PASSWORD", NULL }, 72 | + { "VLDAP_BASEDN", NULL }, 73 | + }; 74 | + 75 | + int i; 76 | + char *key, *val; 77 | + FILE *fs; 78 | + 79 | + if (!init) { /* init file read */ 80 | + snprintf (sbuf, sizeof(sbuf), "%s/etc/ldapconfig", VPOPMAILDIR); 81 | + 82 | + if (NULL != (fs = fopen(sbuf, "r"))) { 83 | + *sbuf = '¥0'; /* path clear */ 84 | + 85 | + while (fgets(sbuf, sizeof(sbuf), fs)) { 86 | + if (' ' == *sbuf || '#' == *sbuf || '¥t' == *sbuf) { 87 | + continue; 88 | + } 89 | + key = strtok_r(sbuf, " ¥t", (char **)&tmpbuf); 90 | + val = strtok_r(NULL, "¥n", (char **)&tmpbuf); 91 | + 92 | + for (i=0; i<PARAM_LISTS; i++) { /* search matched keyname */ 93 | + if (0 == strncmp(param[i].n, key, (size_t)PARAM_NAME_MAXLEN)) { 94 | + break; 95 | + } 96 | + } 97 | + if (i<PARAM_LISTS) { /* matched */ 98 | + param[i].v = safe_strdup(val); 99 | + if (VLDAP_DEBUG) { 100 | + fprintf(stderr, "getconfigparam(): i=%d, key=%s, val=%s¥n", 101 | + i, param[i].n, param[i].v); 102 | + } 103 | + } 104 | + } 105 | + fclose(fs); 106 | + } 107 | + init++; 108 | + } 109 | + 110 | + /* search table */ 111 | + for (i=0; i<PARAM_LISTS; i++) { /* search matched keyname */ 112 | + if (0 == strncmp(param[i].n, name, PARAM_NAME_MAXLEN)) { 113 | + if (param[i].v) { 114 | + return param[i].v; 115 | + } else { 116 | + fprintf(stderr, "Error: null-param: key='%s'.¥n", name); 117 | + exit(1); 118 | + } 119 | + } 120 | + } 121 | + /* not found */ 122 | + fprintf(stderr, "Error: No file: %s/etc/ldapconfig¥n", VPOPMAILDIR); 123 | + exit(1); 124 | + /* return NULL; */ 125 | + } 126 | + /*------------------------------------------------------------*/ 127 | 128 | /***************************************************************************/ 129 | 130 | *************** 131 | *** 305,310 **** 132 | --- 394,402 ---- 133 | memcpy((char *)vpw->pw_clear_passwd, (char *)(*vals), strlen(*vals)); 134 | ldap_value_free(vals); 135 | } 136 | + #else 137 | + vpw->pw_clear_passwd = (char *)safe_malloc(1); 138 | + *(vpw->pw_clear_passwd) = '¥0'; 139 | #endif 140 | 141 | 142 | *************** 143 | *** 478,486 **** 144 | return -99; 145 | } 146 | 147 | ! lm = (LDAPMod **)safe_malloc(sizeof(LDAPMod *) * (NUM_LDAP_FIELDS +1)); 148 | 149 | ! for(i=0;i<NUM_LDAP_FIELDS;++i) { 150 | lm[i] = (LDAPMod *)safe_malloc(sizeof(LDAPMod)); 151 | 152 | memset((LDAPMod *)lm[i], 0, sizeof(LDAPMod)); 153 | --- 570,578 ---- 154 | return -99; 155 | } 156 | 157 | ! lm = (LDAPMod **)safe_malloc(sizeof(LDAPMod *) * (NUM_LDAP_FIELDSW +1)); 158 | 159 | ! for(i=0;i<NUM_LDAP_FIELDSW;++i) { 160 | lm[i] = (LDAPMod *)safe_malloc(sizeof(LDAPMod)); 161 | 162 | memset((LDAPMod *)lm[i], 0, sizeof(LDAPMod)); 163 | *************** 164 | *** 490,496 **** 165 | lm[i]->mod_values[1] = NULL; 166 | } 167 | 168 | ! lm[NUM_LDAP_FIELDS] = NULL; 169 | 170 | /* lm[0] will store : uid / pw_name */ 171 | lm[0]->mod_values[0] = safe_strdup(user); 172 | --- 582,599 ---- 173 | lm[i]->mod_values[1] = NULL; 174 | } 175 | 176 | ! /* ----ZZZZ---- */ 177 | ! lm[NUM_LDAP_FIELDS+0]->mod_values[0] = safe_strdup(gecos); 178 | ! lm[NUM_LDAP_FIELDS+1]->mod_values[0] = safe_strdup(gecos); 179 | ! 180 | ! lm[NUM_LDAP_FIELDS+2]->mod_values[0] = safe_strdup("top"); 181 | ! lm[NUM_LDAP_FIELDS+3]->mod_values[0] = safe_strdup("person"); 182 | ! lm[NUM_LDAP_FIELDS+4]->mod_values[0] = safe_strdup("organizationalPerson"); 183 | ! lm[NUM_LDAP_FIELDS+5]->mod_values[0] = safe_strdup("inetOrgPerson"); 184 | ! /*lm[NUM_LDAP_FIELDS+6]->mod_values[0] = safe_strdup("alter1");*/ 185 | ! /* ----ZZZZ---- */ 186 | ! lm[NUM_LDAP_FIELDS+6] = NULL; 187 | ! 188 | 189 | /* lm[0] will store : uid / pw_name */ 190 | lm[0]->mod_values[0] = safe_strdup(user); 191 | *************** 192 | *** 504,514 **** 193 | } 194 | 195 | lm[1]->mod_values[0] = (char *) safe_malloc(strlen(crypted) + 7 + 1); 196 | ! #ifdef MD5_PASSWORDS 197 | ! 198 | snprintf(lm[1]->mod_values[0], strlen(crypted) + 7 + 1, "{MD5}%s", crypted); 199 | #else 200 | - 201 | snprintf(lm[1]->mod_values[0], strlen(crypted) + 7 + 1, "{crypt}%s", crypted); 202 | #endif 203 | 204 | --- 607,617 ---- 205 | } 206 | 207 | lm[1]->mod_values[0] = (char *) safe_malloc(strlen(crypted) + 7 + 1); 208 | ! #if defined(ENABLE_PLANEPASSWORD) 209 | ! snprintf(lm[1]->mod_values[0], strlen(password), "%s", password); 210 | ! #elif defined(MD5_PASSWORDS) 211 | snprintf(lm[1]->mod_values[0], strlen(crypted) + 7 + 1, "{MD5}%s", crypted); 212 | #else 213 | snprintf(lm[1]->mod_values[0], strlen(crypted) + 7 + 1, "{crypt}%s", crypted); 214 | #endif 215 | 216 | *************** 217 | *** 565,571 **** 218 | /* set dn to be of the format : 219 | * uid=someuser, ou=somedomain,o=vpopmail 220 | */ 221 | ! len = 4 + strlen(user) + 2 + strlen(VLDAP_BASEDN) + 4 + strlen(domain) + 1; 222 | dn = (char *) safe_malloc(len); 223 | memset((char *)dn, 0, len); 224 | snprintf(dn, len, "uid=%s, %s", user, dn_tmp); 225 | --- 668,675 ---- 226 | /* set dn to be of the format : 227 | * uid=someuser, ou=somedomain,o=vpopmail 228 | */ 229 | ! len = 4 + strlen(user) + 2 + strlen(getconfigparam("VLDAP_BASEDN")) 230 | ! + 4 + strlen(domain) + 1; 231 | dn = (char *) safe_malloc(len); 232 | memset((char *)dn, 0, len); 233 | snprintf(dn, len, "uid=%s, %s", user, dn_tmp); 234 | *************** 235 | *** 610,616 **** 236 | } 237 | } 238 | 239 | ! lm = (LDAPMod **)safe_malloc(sizeof(LDAPMod *) * 2); 240 | 241 | lm[0] = (LDAPMod *)safe_malloc(sizeof(LDAPMod)); 242 | 243 | --- 714,720 ---- 244 | } 245 | } 246 | 247 | ! lm = (LDAPMod **)safe_malloc(sizeof(LDAPMod *) * 3); 248 | 249 | lm[0] = (LDAPMod *)safe_malloc(sizeof(LDAPMod)); 250 | 251 | *************** 252 | *** 653,663 **** 253 | * lm will be the ldap propoerties of somedomain.com 254 | */ 255 | ret = ldap_add_s(ld, dn, lm); 256 | ! 257 | if (ret != LDAP_SUCCESS) { 258 | ldap_perror(ld,"Error"); 259 | return -99; 260 | ! } 261 | 262 | safe_free((void **) &dn); 263 | safe_free((void **) &lm[0]->mod_type); 264 | --- 757,767 ---- 265 | * lm will be the ldap propoerties of somedomain.com 266 | */ 267 | ret = ldap_add_s(ld, dn, lm); 268 | ! /* 269 | if (ret != LDAP_SUCCESS) { 270 | ldap_perror(ld,"Error"); 271 | return -99; 272 | ! }*/ 273 | 274 | safe_free((void **) &dn); 275 | safe_free((void **) &lm[0]->mod_type); 276 | *************** 277 | *** 671,677 **** 278 | 279 | if (ret != LDAP_SUCCESS) { 280 | if (ret == LDAP_ALREADY_EXISTS) 281 | ! return VA_USERNAME_EXISTS; 282 | return -99; 283 | } 284 | 285 | --- 775,781 ---- 286 | 287 | if (ret != LDAP_SUCCESS) { 288 | if (ret == LDAP_ALREADY_EXISTS) 289 | ! return VA_SUCCESS /*VA_USERNAME_EXISTS*/ ; /*ZZZZ*/ 290 | return -99; 291 | } 292 | 293 | *************** 294 | *** 692,698 **** 295 | return -99; 296 | } 297 | 298 | ! len = strlen(domain) + strlen(VLDAP_BASEDN) + 4 + 1; 299 | 300 | /* dn will be of the format : 301 | * ou=somedomain.com,o=vpopmail 302 | --- 796,802 ---- 303 | return -99; 304 | } 305 | 306 | ! len = strlen(domain) + strlen(getconfigparam("VLDAP_BASEDN")) + 4 + 1; 307 | 308 | /* dn will be of the format : 309 | * ou=somedomain.com,o=vpopmail 310 | *************** 311 | *** 747,753 **** 312 | return -99; 313 | } 314 | 315 | ! len = 4 + strlen(user) + 2 + strlen(VLDAP_BASEDN) + 4 + strlen(domain) + 1; 316 | 317 | /* make dn_tmp to be of the format 318 | * ou=somedomain.com,o=vpopmail 319 | --- 851,858 ---- 320 | return -99; 321 | } 322 | 323 | ! len = 4 + strlen(user) + 2 + strlen(getconfigparam("VLDAP_BASEDN")) 324 | ! + 4 + strlen(domain) + 1; 325 | 326 | /* make dn_tmp to be of the format 327 | * ou=somedomain.com,o=vpopmail 328 | *************** 329 | *** 848,858 **** 330 | lm[0]->mod_values[0] = safe_strdup(inpw->pw_name); 331 | 332 | lm[1]->mod_values[0] = safe_malloc(strlen(inpw->pw_passwd) + 7 + 1); 333 | - #ifdef MD5_PASSWORDS 334 | 335 | ! snprintf(lm[1]->mod_values[0], strlen(inpw->pw_passwd) + 7 + 1, "{MD5}%s", inpw->pw_passwd); 336 | #else 337 | - 338 | snprintf(lm[1]->mod_values[0], strlen(inpw->pw_passwd) + 7 + 1, "{crypt}%s", inpw->pw_passwd); 339 | #endif 340 | 341 | --- 953,966 ---- 342 | lm[0]->mod_values[0] = safe_strdup(inpw->pw_name); 343 | 344 | lm[1]->mod_values[0] = safe_malloc(strlen(inpw->pw_passwd) + 7 + 1); 345 | 346 | ! #if defined(ENABLE_PLANEPASSWORD) 347 | ! snprintf(lm[1]->mod_values[0], strlen(inpw->pw_passwd), "%s", 348 | ! inpw->pw_passwd); 349 | ! #elif defined(MD5_PASSWORDS) 350 | ! snprintf(lm[1]->mod_values[0], strlen(inpw->pw_passwd) + 7 + 1, 351 | ! "{MD5}%s", inpw->pw_passwd); 352 | #else 353 | snprintf(lm[1]->mod_values[0], strlen(inpw->pw_passwd) + 7 + 1, "{crypt}%s", inpw->pw_passwd); 354 | #endif 355 | 356 | *************** 357 | *** 882,888 **** 358 | return -98; 359 | } 360 | 361 | ! len = 4 + strlen(inpw->pw_name) + 2 + strlen(VLDAP_BASEDN) + 4 + strlen(domain) + 1; 362 | dn = (char *) safe_malloc (len); 363 | memset((char *)dn, 0, len); 364 | 365 | --- 990,997 ---- 366 | return -98; 367 | } 368 | 369 | ! len = 4 + strlen(inpw->pw_name) + 2 370 | ! + strlen(getconfigparam("VLDAP_BASEDN")) + 4 + strlen(domain) + 1; 371 | dn = (char *) safe_malloc (len); 372 | memset((char *)dn, 0, len); 373 | 374 | *************** 375 | *** 1317,1328 **** 376 | int compose_dn (char **dn, char *domain) { 377 | size_t len = 0; 378 | 379 | ! len = strlen(domain) + strlen(VLDAP_BASEDN) + 5; 380 | 381 | *dn = (char *)safe_malloc(len); 382 | memset((char *)*dn, 0, len); 383 | 384 | ! snprintf(*dn,len,"ou=%s,%s",domain,VLDAP_BASEDN); 385 | 386 | return 0; 387 | 388 | --- 1426,1446 ---- 389 | int compose_dn (char **dn, char *domain) { 390 | size_t len = 0; 391 | 392 | ! len = strlen(domain) + strlen(getconfigparam("VLDAP_BASEDN")) + 5; 393 | 394 | *dn = (char *)safe_malloc(len); 395 | memset((char *)*dn, 0, len); 396 | 397 | ! if (! *domain 398 | ! #if SINGLEDOMAIN_DEFAULTDOMAIN 399 | ! || 0 == strncmp(domain, SINGLEDOMAIN_DEFAULTDOMAIN, 400 | ! strlen(SINGLEDOMAIN_DEFAULTDOMAIN)) 401 | ! #endif 402 | ! ) { 403 | ! snprintf(*dn,len,"%s",getconfigparam("VLDAP_BASEDN")); 404 | ! } else { 405 | ! snprintf(*dn,len,"ou=%s,%s",domain,getconfigparam("VLDAP_BASEDN")); 406 | ! } 407 | 408 | return 0; 409 | 410 | *************** 411 | *** 1336,1342 **** 412 | three steps fail the whole auth_connection failed */ 413 | verrori = VA_NO_AUTH_CONNECTION; 414 | 415 | ! ld = ldap_init(VLDAP_SERVER, VLDAP_PORT); 416 | if (ld == NULL) { 417 | ldap_perror(ld,"Failed to inititialize LDAP-Connection"); 418 | return -99; 419 | --- 1454,1461 ---- 420 | three steps fail the whole auth_connection failed */ 421 | verrori = VA_NO_AUTH_CONNECTION; 422 | 423 | ! ld = ldap_init(getconfigparam("VLDAP_SERVER"), 424 | ! atoi(getconfigparam("VLDAP_PORT"))); 425 | if (ld == NULL) { 426 | ldap_perror(ld,"Failed to inititialize LDAP-Connection"); 427 | return -99; 428 | *************** 429 | *** 1346,1352 **** 430 | ldap_perror(ld,"Failed to set LDAP-Option"); 431 | return -99; 432 | } 433 | ! ret = ldap_simple_bind_s(ld, VLDAP_USER, VLDAP_PASSWORD); 434 | if (ret != LDAP_SUCCESS) { 435 | ldap_perror(ld,"Error"); 436 | return (VA_NO_AUTH_CONNECTION); 437 | --- 1465,1472 ---- 438 | ldap_perror(ld,"Failed to set LDAP-Option"); 439 | return -99; 440 | } 441 | ! ret = ldap_simple_bind_s(ld, getconfigparam("VLDAP_USER"), 442 | ! getconfigparam("VLDAP_PASSWORD")); 443 | if (ret != LDAP_SUCCESS) { 444 | ldap_perror(ld,"Error"); 445 | return (VA_NO_AUTH_CONNECTION); 446 | diff -c vpopmail-5.4.0-org/vldap.h vpopmail-5.4.0/vldap.h 447 | *** vpopmail-5.4.0-org/vldap.h Mon Dec 22 21:08:10 2003 448 | --- vpopmail-5.4.0/vldap.h Thu Feb 5 23:15:01 2004 449 | *************** 450 | *** 28,38 **** 451 | --- 28,45 ---- 452 | #ifndef VPOPMAIL_LDAP_H 453 | #define VPOPMAIL_LDAP_H 454 | 455 | + #if 0 456 | + #define SINGLEDOMAIN_DEFAULTDOMAIN "mysubdomain.mydomain" 457 | + #define ENABLE_PLANEPASSWORD 458 | + #endif 459 | + 460 | + /* 461 | #define VLDAP_SERVER "localhost" 462 | #define VLDAP_PORT LDAP_PORT 463 | #define VLDAP_USER "cn=vpopmailuser, o=vpopmail" 464 | #define VLDAP_PASSWORD "vpoppasswd" 465 | #define VLDAP_BASEDN "o=vpopmail" 466 | + */ 467 | 468 | #define MAX_BUFF 500 469 |
----- src/vpopmail-5.4.0/GO_vpopmail.sh : --------------------------- 1 | #!/bin/sh 2 | # /home/nec/src/vpopmail-5.3.28 3 | # /home/nec/src/vpopmail-5.4.0 4 | # 5 | #--enable-users-big-dir=n ¥ 5.4.0 obsorute 6 | #--enable-defaultquota=n ¥ 5.4.0 obsorute 7 | # 8 | env CC=gcc ./configure --enable-roaming-users=y ¥ 9 | --enable-passwd=y ¥ 10 | --enable-clear-passwd=y ¥ 11 | --enable-tcpserver-file=/etc/tcpserver/smtp.tcprule ¥ 12 | --enable-apop=n ¥ 13 | --enable-auth-module=ldap ¥ 14 | --enable-qmail-ext=y
# make # make install-strip
----- /home/vpopmail/etc/ldapconfig : ------------------------------- 1 | # /home/vpopmail/etc/ldapconfig 2 | # vpopmail-ldap configuration file: 3 | # 20031022: vldap.c implement by k-sasamori@elsd.mt.nec.co.jp 4 | # 5 | # please edit this file and copy to '‾vpopmail/etc/ldapconfig'. 6 | # 7 | VLDAP_SERVER localhost 8 | 9 | VLDAP_PORT 389 10 | 11 | VLDAP_USER cn=Manager,dc=cis,dc=yamanashi-u 12 | 13 | VLDAP_PASSWORD passwd // パスワード例: 'passwd' 14 | 15 | VLDAP_BASEDN dc=cis,dc=yamanashi-u
courier-imap は vpopmailが扱うバーチャルドメインに対応した pop3/imap4サーバである。 本研究では、pop3については、qmail-pop3dが対応しているAPOPを利用するため、imap4のみ利用する。
----- ../courier-imap-2.2.1-necpatch.patch : ------------------------ 1 | diff -r courier-imap-2.2.1/authlib/authldap.h courier-imap-2.2.1-necpatch/authlib/authldap.h 2 | 24a25,27 3 | > #define VPOPMAIL_UID 89 4 | > #define VPOPMAIL_GID 89 5 | > 6 | diff -r courier-imap-2.2.1/authlib/authldaplib.c courier-imap-2.2.1-necpatch/authlib/authldaplib.c 7 | 948c948 8 | < syslog(LOG_DAEMON|LOG_CRIT,"Nombre de r蜩ulat: %d¥n",ldap_count_entries(my_ldap_fp,result)); 9 | --- 10 | > syslog(LOG_DAEMON|LOG_CRIT,"Number of result: %d¥n",ldap_count_entries(my_ldap_fp,result)); 11 | 997a998 12 | > au=VPOPMAIL_UID; /*ZZZ*/ 13 | 1013a1015 14 | > ag=VPOPMAIL_GID; /*ZZZ*/ 15 | 1060c1062 16 | < if (au == 0 || ag == 0) 17 | --- 18 | > if (au == 0 /* || ag == 0*/) 19 | 1122a1125,1126 20 | > if (p && strncasecmp(p, "{MD5}", 5) == 0) 21 | > p += 5; /* For authcheckpassword */ 22 | diff -r courier-imap-2.2.1/imap/imapd.c courier-imap-2.2.1-necpatch/imap/imapd.c 23 | 82c82 24 | < #define SHARED "shared" 25 | --- 26 | > #define SHARED "#shared" 27 | 359a360,363 28 | > const char * envp = getenv("IMAP_PERSONAL_NAMESPACE_AT_TOP_LEVEL"); 29 | > const int isTopLevelEnabled = envp && atoi(envp); 30 | > 31 | > 32 | 366,367c370,374 33 | < free(p); 34 | < return (0); 35 | --- 36 | > if (!isTopLevelEnabled) 37 | > { 38 | > free(p); 39 | > return (0); 40 | > } 41 | 369,370c376,377 42 | < 43 | < arg += sizeof(INBOX)-1; 44 | --- 45 | > else if (!isTopLevelEnabled) 46 | > arg += sizeof(INBOX)-1; 47 | 374c381 48 | < else if (*arg++ != '.') 49 | --- 50 | > else if (!isTopLevelEnabled && *arg++ != '.') 51 | 379c386,388 52 | < else 53 | --- 54 | > else if (isTopLevelEnabled) 55 | > arg=maildir_folderdir(0, (*arg == '.') ? arg + 1 : arg); 56 | > else 57 | 1774a1784,1786 58 | > const char * envp = getenv("IMAP_PERSONAL_NAMESPACE_AT_TOP_LEVEL"); 59 | > char *arg; 60 | > 61 | 1785c1797,1811 62 | < fprintf(newfp, "%s¥n", buf); 63 | --- 64 | > p = buf; 65 | > #if HAVE_STRNCASECMP 66 | > if (!strncasecmp(buf, INBOX, sizeof(INBOX)-1)) 67 | > #else 68 | > if (!strnicmp(buf, INBOX, sizeof(INBOX)-1)) 69 | > #endif 70 | > { 71 | > if (envp && atoi(envp) && buf[sizeof(INBOX)] != 0) 72 | > { 73 | > p = buf + sizeof(INBOX); 74 | > } 75 | > } 76 | > arg = valid_mailbox_name(p,0); 77 | > if (arg && !access(arg, 0)) 78 | > fprintf(newfp, "%s¥n", p); 79 | 1810c1836,1838 80 | < 81 | --- 82 | > const char * envp = getenv("IMAP_PERSONAL_NAMESPACE_AT_TOP_LEVEL"); 83 | > char *arg; 84 | > 85 | 1812c1840,1852 86 | < if (sub_strcmp(buf, f) == 0) 87 | --- 88 | > p = buf; 89 | > #if HAVE_STRNCASECMP 90 | > if (!strncasecmp(buf, INBOX, sizeof(INBOX)-1)) 91 | > #else 92 | > if (!strnicmp(buf, INBOX, sizeof(INBOX)-1)) 93 | > #endif 94 | > { 95 | > if (envp && atoi(envp) && buf[sizeof(INBOX)] != 0) 96 | > { 97 | > p = buf + sizeof(INBOX); 98 | > } 99 | > } 100 | > if (sub_strcmp(p, f) == 0) 101 | 1814c1854,1856 102 | < fprintf(newfp, "%s¥n", buf); 103 | --- 104 | > arg = valid_mailbox_name(p,0); 105 | > if (!access(arg, 0)) 106 | > fprintf(newfp, "%s¥n", p); 107 | 3216a3259,3260 108 | > const char * envp = getenv("IMAP_PERSONAL_NAMESPACE_AT_TOP_LEVEL"); 109 | > 110 | 3219,3220c3263,3269 111 | < writes("* NAMESPACE ((¥"INBOX.¥" ¥".¥")) NIL ((¥"" 112 | < SHARED ".¥" ¥".¥"))¥r¥n"); 113 | --- 114 | > 115 | > if (envp && atoi(envp)) 116 | > writes("* NAMESPACE ((¥"¥" ¥".¥")) NIL ((¥"" 117 | > SHARED ".¥" ¥".¥"))¥r¥n"); 118 | > else 119 | > writes("* NAMESPACE ((¥"INBOX.¥" ¥".¥")) NIL ((¥"" 120 | > SHARED ".¥" ¥".¥"))¥r¥n"); 121 | diff -r courier-imap-2.2.1/imap/mailboxlist.c courier-imap-2.2.1-necpatch/imap/mailboxlist.c 122 | 313a314,315 123 | > const char * envp = getenv("IMAP_PERSONAL_NAMESPACE_AT_TOP_LEVEL"); 124 | > char *arg; 125 | 316,317c318,341 126 | < folder_entry(buf, hier, found_hier, 127 | < folders, hierarchies); 128 | --- 129 | > if (envp && atoi(envp)) 130 | > { 131 | > q = buf; 132 | > #if HAVE_STRNCASECMP 133 | > if (!strncasecmp(buf, INBOX, sizeof(INBOX)-1) 134 | > #else 135 | > if (!strnicmp(buf, INBOX, sizeof(INBOX)-1) 136 | > #endif 137 | > && buf[sizeof(INBOX)] != 0) 138 | > { 139 | > q = buf + sizeof(INBOX); 140 | > } 141 | > arg = valid_mailbox_name(q,0); 142 | > if (arg && !access(arg, 0)) 143 | > folder_entry(q, hier, found_hier, 144 | > folders, hierarchies); 145 | > } 146 | > else 147 | > { 148 | > arg = valid_mailbox_name(buf,0); 149 | > if (arg && !access(arg, 0)) 150 | > folder_entry(buf, hier, found_hier, 151 | > folders, hierarchies); 152 | > } 153 | 378a403 154 | > const char * envp = getenv("IMAP_PERSONAL_NAMESPACE_AT_TOP_LEVEL"); 155 | 398,400c423,427 156 | < 157 | < if (strcmp(de->d_name, ".")) 158 | < strcat(p, de->d_name); 159 | --- 160 | > if (envp && atoi(envp) && strcmp(de->d_name, ".")) 161 | > strcpy(p, de->d_name + 1); 162 | > else 163 | > if (strcmp(de->d_name, ".")) 164 | > strcat(p, de->d_name); 165 | 575a603,607 166 | > const char * envp = getenv("IMAP_PERSONAL_NAMESPACE_AT_TOP_LEVEL"); 167 | > 168 | > if (envp && atoi(envp)) 169 | > return (match_recursive(name, pattern, HIERCH)); 170 | >
----- GO_courier-imap.sh : ------------------------------------------ 1 | #!/bin/sh 2 | # [ for solaris sample:] 3 | #env CC=gcc CFLAGS=-O3 ¥ 4 | #CPPFLAGS='-I/usr/local/BerkeleyDB.4.1/include -I/usr/local/ssl/include ' ¥ 5 | #LDFLAGS='-R/usr/local/lib:/usr/lib -L/usr/local/lib -L/usr/local/ssl/lib -L/usr/local/BerkeleyDB.4.1/lib' ¥ 6 | #./configure --without-authdaemon --with-authvchkpw --disable-root-check ¥ 7 | # --with-db=db --prefix=/usr/local/courier-imap ¥ 8 | # --enable-workarounds-for-imap-client-bugs --enable-unicode 9 | # 10 | env CC=gcc CFLAGS=-O3 ¥ 11 | CPPFLAGS='-I/usr/local/ssl/include ' ¥ 12 | LDFLAGS='-R/usr/local/lib:/usr/lib -L/usr/local/lib -L/usr/local/ssl/lib' ¥ 13 | ./configure --without-authdaemon --with-authvchkpw --disable-root-check ¥ 14 | --with-db=db --prefix=/usr/local/courier-imap ¥ 15 | --enable-workarounds-for-imap-client-bugs --enable-unicode ¥ 16 | --with-redhat
$ make # su # make install-strip
各種ソフトウェアのコンパイルが終了したら、いよいよ設定して動かすわけであるが、 本研究では、設定ファイルのサンプルと設定のポイントのみを述べるに留め、 他の文献や付属ドキュメントに既に記載されてよく見受けられる内容については割愛することにする。
[root@ldap2 src]# catn -w /var/qmail/control/* ----- /var/qmail/control/_locals : ---------------------------------- 1 | ldap2.yamanashi.ac.jp ----- /var/qmail/control/defaultdomain : ---------------------------- 1 | ldap2.yamanashi.ac.jp ----- /var/qmail/control/envnoathost : ------------------------------ 1 | ldap2.yamanashi.ac.jp ----- /var/qmail/control/ldapbasedn : ------------------------------- 1 | dc=cis,dc=yamanashi-u ----- /var/qmail/control/ldapdefaultdotmode : ----------------------- 1 | both ----- /var/qmail/control/ldapgid : ---------------------------------- 1 | 89 ----- /var/qmail/control/ldaplogin : -------------------------------- 1 | cn=Manager,dc=cis,dc=yamanashi-u ----- /var/qmail/control/ldappassword : ----------------------------- 1 | passwd /// パスワード例 ----- /var/qmail/control/ldapserver : ------------------------------- 1 | 127.0.0.1 ----- /var/qmail/control/ldapuid : ---------------------------------- 1 | 89 ----- /var/qmail/control/me : --------------------------------------- 1 | ldap2.yamanashi.ac.jp ----- /var/qmail/control/plusdomain : ------------------------------- 1 | ac.jp ----- /var/qmail/control/rcpthosts : -------------------------------- 1 | ldap2.yamanashi.ac.jp ----- /var/qmail/control/smtproutes : ------------------------------- 1 | :mailgateway.yamanashi.ac.jp ----- /var/qmail/control/virtualdomains : --------------------------- 1 | ldap2.yamanashi.ac.jp:ldap2.yamanashi.ac.jp
----- /etc/tcpserver/Makefile : ------------------------------------- 1 | # Makefile: 20030402: k-sasamori 2 | .SUFFIXES: .tcprule .cdb 3 | .tcprule.cdb: 4 | /usr/local/bin/tcprules $@ $<.tmp < $< 5 | 6 | all: pop3.cdb imap4.cdb smtp.cdb
----- /etc/tcpserver/smtp.tcprule : --------------------------------- 1 | # /etc/tcpserver/tcp.smtp: 2 | # configuration of smtp(qmail-smtpd) service 3 | # 4 | # if this file modified, do comamnd: 5 | # ( cd /etc/tcpserver ; tcprules tcp.smtp.cdb tcp.smtp.tmp < tcp.smtp ) 6 | # 7 | 127.:allow,RELAYCLIENT="" 8 | 133.23.:allow,RELAYCLIENT="" 9 | :allow
○ | 192.168.:allow × | 172.16. :allow × | 172.16.: deny
----- /var/qmail/supervise/qmail/run : ------------------------------ 1 | #!/bin/sh 2 | # /var/qmail/supervise/qmail/run : 3 | # 4 | exec env - PATH="/var/qmail/bin:$PATH" ¥ 5 | DEBUGLEVEL="0" LOGLEVEL="0" ¥ 6 | qmail-start ./Maildir/ splogger qmail ----- /var/qmail/supervise/smtpd/run : ------------------------------ 1 | #!/bin/sh 2 | # /var/qmail/supervise/smtpd/run : 3 | # smtpd starting script: 4 | # 5 | exec env - PATH="/var/qmail/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin" ¥ 6 | envdir /var/qmail/supervise/smtpd/env ¥ 7 | tcpserver -x /etc/tcpserver/smtp.cdb -RHv -l0 -u 82 -g 81 0 smtp ¥ 8 | /var/qmail/bin/qmail-smtpd 2>&1 ----- /var/qmail/supervise/pop3/run : ------------------------------- 1 | #!/bin/sh 2 | # /var/qmail/supervise/imapd/run : 3 | # vpopmail-pop3d starting script: 4 | # 5 | #------ 6 | PORT=pop3 7 | #PORT=995 8 | #SSLOPTION='-s -n /usr/local/courier-imap/share/imapd.pem' 9 | DOMAIN=ldap2.yamanashi.ac.jp 10 | #------ 11 | exec env - PATH="/usr/local/bin:/usr/local/courier-imap/bin:/usr/local/courier-imap/sbin" ¥ 12 | AUTHUSER=/home/vpopmail/bin/vchkpw ¥ 13 | tcpserver -x /etc/tcpserver/pop3.cdb -vRH -l0 -c40 -u0 -g0 ¥ 14 | $SSLOPTION ¥ 15 | 0 $PORT pop3login ¥ 16 | /home/vpopmail/bin/vchkpw ¥ 17 | /usr/local/courier-imap/bin/pop3d Maildir ¥ 18 | 2>&1 ----- /var/qmail/supervise/imap/run : ------------------------------- 1 | #!/bin/sh 2 | # /var/qmail/supervise/imaps/run : 3 | # courier-imap starting script: 4 | # 2004.02.06 nec@yamanashi.ac.jp 5 | #------ 6 | PORT=imap 7 | #PORT=993 8 | #SSLOPTION='-s -n /usr/local/courier-imap/share/imapd.pem' 9 | #------ 10 | COURIER_IMAP_PATH='/usr/local/courier-imap/libexec/authlib' 11 | AUTHMODULES="authvchkpw" 12 | LIBAUTHMODULES="" 13 | for f in `echo $AUTHMODULES` 14 | do 15 | LIBAUTHMODULES="$LIBAUTHMODULES $COURIER_IMAP_PATH/$f" 16 | done 17 | #------ 18 | exec env - PATH="/usr/local/bin:/usr/local/courier-imap/bin:/usr/local/courier-imap/sbin" ¥ 19 | IMAP_IDLE_TIMEOUT=60 ¥ 20 | IMAP_CAPABILITY="IMAP4rev1 CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT AUTH=CRAM-SHA1" ¥ 21 | IMAP_CAPABILITY_TLS="$IMAP_CAPABILITY AUTH=PLAIN" ¥ 22 | IMAP_DISABLETHREADSORT=0 ¥ 23 | IMAP_CHECK_ALL_FOLDERS=0 ¥ 24 | IMAP_OBSOLETE_CLIENT=0 ¥ 25 | IMAP_ULIMITD=65536 ¥ 26 | IMAP_USELOCKS=0 ¥ 27 | IMAP_EMPTYTRASH=7 ¥ 28 | IMAP_MOVE_EXPUNGE_TO_TRASH=0 ¥ 29 | IMAP_PERSONAL_NAMESPACE_AT_TOP_LEVEL=0 ¥ 30 | ¥ 31 | IMAP_STARTTLS=YES ¥ 32 | TLS_PROTOCOL=TLS1 ¥ 33 | AUTHUSER=/usr/local/courier-imap/libexec/authlib/authvchkpw ¥ 34 | ¥ 35 | tcpserver -x /etc/tcpserver/imap4.cdb -vRH -c40 -u0 -g0 ¥ 36 | $SSLOPTION ¥ 37 | 0 $PORT imaplogin $LIBAUTHMODULES ¥ 38 | /usr/local/courier-imap/bin/imapd Maildir ¥ 39 | 2>&1
----- /var/qmail/supervise/pop3s/run : ------------------------------- 1 | #!/bin/sh 2 | # /var/qmail/supervise/imapd/run : 3 | # vpopmail-pop3d starting script: 4 | # 5 | #------ 6 | ##PORT=pop3 7 | PORT=995 8 | SSLOPTION='-s -n /usr/local/courier-imap/share/imapd.pem' : (以下 /var/qmail/supervise/pop3/run と同一につき省略) ----- /var/qmail/supervise/imaps/run : ------------------------------- 1 | #!/bin/sh 2 | # /var/qmail/supervise/imaps/run : 3 | # courier-imap starting script: 4 | # 2004.02.06 nec@yamanashi.ac.jp 5 | #------ 6 | ##PORT=imap 7 | PORT=993 8 | SSLOPTION='-s -n /usr/local/courier-imap/share/imapd.pem' : (以下 /var/qmail/supervise/imap/run と同一につき省略)
# mkdir /usr/local/ssl/CA # cd /usr/local/ssl/CA # mkdir certs crl newcerts private # cp /dev/null index.txt # echo "01" > serial # chmod 700 private
# openssl genrsa -rand /var/log/maillog -out cakey.pem 1024
# openssl req -new -key cacert.pem -out ca.csr
# openssl x509 -req -in ca.csr -signkey cakey.pem -out cacert.pem
# cd /usr/local/apache2/conf/ssl /// 〜みたいな必要な箇所に移動して実行 # openssl genrsa -rand /var/log/maillog -out server.key 1024
# openssl req -new -key server.key -out server.csr
# openssl ca -out server.crt -infiles server.csr (中略) 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated # ls -l -rw-r--r-- 1 root other 4011 Oct 24 15:23 server.crt -rw-r--r-- 1 root other 802 Oct 24 15:05 server.csr -rw-r--r-- 1 root other 887 Oct 24 15:03 server.key
以下のソフトウェアは、qmailやvpopmailと一緒に使われることの多いものである。 これらはLDAP対応コードが無くとも独立して動く。ここでは簡単な紹介に留めることとする。
qmailのキュー: /var/qmail/queue/{info,mess,local,remote}を管理できるperlスクリプトである。
autorespondは、vacationなどに相当する一定のメッセージを自動返信するツールです。 qmailadmin が 利用しています。
ezmlm, ezmlm-idxは qmailの拡張アドレス(.qmail-username-*)を利用した メーリングリスト管理プログラムである。ezmlm-idx は オリジナルのezmlmに種々の拡張を施す パッチである。
# tar xvzf ezmlm-0.53.tar.gz # tar xvzf ezmlm-idx-0.40.tar.gz # mv ezmlm-idx-0.40/* ezmlm-0.53/ # cd ezmlm-0.53 # patch < idx.patch # make clean # make # make man # cp ezmlmrc.jp ezmlmrc # make setup
qmailadminは、vpopmailがサポートする仮想アカウントユーザ・マルチドメインのメールシステム やメーリングリストezmlmの管理がWebから実行できるC言語によるCGIプログラムである。
# ./configure --enable-cgibindir=/usr/local/apache2/cgi-bin ¥ > --enable-htmldir=/usr/local/apache2/htdocs ¥ > --enable-imagedir=/usr/local/apache2/htdocs/images/qmailadmin ¥ > --enable-vpopmaildir=/home/vpopmail # make && make install
SquirrelMail は Webサーバ上のPHPスクリプトで動く、Webメールソフトウェアである。 大変完成度が高く、プラグインで機能を追加できるようになっている。 一部のプラグインの日本語化において若干不具合も見られるが、オープンソースでPHPなので 自由に修正・改造できるのが有難い。
本研究により、ローカルアカウントを使用せず、
全てのユーザをLDAPアカウントに格納したメールサーバシステムを構築し、
実機にて稼動・動作確認することが出来た。
以下に、ここまでで構築・動作が確認できた基本的機能を項目としてまとめる。:
あわせて、構築できたLDAPメールサーバシステムのデータフロー図をまとめとして引用しておく。:
図2:LDAPメールシステム メールデータフロー図
今後としては、以下の事項について、続けて実装と動作確認を行ないたい。:以下、閑話休題的に、本研究にて気がついた点を述べたいと思う。
qmailのコードは比較的読み難い。例えば、ヌルポインタNULLも、ヌル文字 '¥0'も
同じ 0 と書かれているし、重要な変数も遠慮なく1文字変数名だったりする。
また、コメントも少ないほうといえるだろう。
このため、LDAP対応コードを修正するにも若干の苦労を要した。
ただし、セキュリティホールなどの
脆弱性が無いように、C標準ライブラリ/POSIX標準ライブラリをほとんど使用せず、
独自のライブラリを作成し利用している点は、特筆すべきであろう。
qmail-1.03がリリースされてから既に 6年が経過しようとしているのも驚嘆に値すると同時に、
qmailのセキュリティの高さを示すものと言えるだろう。
また、courier-imapのLDAP対応コードでは、いきなりフランス語でエラーメッセージを syslogに出力しており驚いた。別に多言語対応しているわけでなく、 ソースにフランス語でエラーメッセージが埋め込まれていた。豪快だ。 vpopmailでも、よくみるとコメントの英語のスペルもいくつかロシア風に間違っていたりする。 世界中のいろんな人がコードに参加しているというのを実感されられた場面であった。
日々更新や改良が意欲的に続けられているオープンソースでは、不具合がつきものである。 なぜか動かなかったり、完成度が中途半端に低かったりすることはよくあることだ。 ここで、市販のソフトウェアだと、開発元または販売元に問い合わせなければならず、時間も掛かるし 解決できないことがよくある。カスタマイズしたくてもできないことが多い。 ところが、オープンソースでは、なんと、ソースが読めさえすれば、自分で不具合箇所を発見できるし、 修正までできてしまう。カスタマイズも(ライセンスに従う限り)自由である。 昨今では、googleなどの検索エンジンを使うことにより、自分が遭遇している問題の解決策が あっさり見つかってしまうこともよくある。 当たり前のことではあるが、今回改めてオープンソースというものの重要性を再認識することになった。
最後に、本メールサーバシステムを構築・評価するに当たり、貴重な助言や実際の評価をして頂いた 山梨大学総合情報処理センターの皆様、 小職の所属する第1官庁システム開発事業部第1文教システムグループの諸先輩方、および、 今回利用させて頂いたソフトウェアをはじめとして、重要な役割をする各ソフトウェアを 無償にて公開しているオープンソースソフトウェアの作者に感謝する。