2019年4月14日日曜日

Samba4.8 における idmap からのユーザ毎ホームディレクトリパスに苦しむ(回避策のみで解決せず)

何年ぶりかで Samba(Samba 4.8 on CentOS 7) のファイルサーバ構築をやってるのでメモ。AD と LDAP が混在したような環境の中で,あるユーザが UNIX からも Windows からも自身の同じホームディレクトリにアクセスしたいっていう大学とかにはよくある構成(今回のこの Samba はドメインコントローラの役割は担わない)。

設定はほぼ終えた。が,一点困っているのは,上記のような構成において[homes] セクション内の %H 変数で得られるホームディレクトリのパスが template homedir ディレクティブの設定に固定されてしまうということ。今回はユーザ毎にホームディレクトリのパス形式が違うのでこれだと困る。なので NSS から取得できる値にしたい(getpwnam()で取れるやつ)。LDAP の homeDirectory 属性に設定されているやつでも良い。

しかし,顧客要件から設定は security = ads が前提。この場合 Samba 4.8 からは winbind 必須とのこと(Samba 4.8 のリリースノート参照)。idmap_nss と idmap_rfc2307(LDAPをバックエンドにする) を試したが、どちらも sid-uid のマッピングは成功するものの、ホームディレクトリは template homedir の値になってしまう。どうも winbind はマッピングに関連する属性(uid, uidNumber, cn , gidNumber等)しかバックエンドから取得せず,それ以外は自前で処理(template xxxxから)してしまう仕様ようだ。Web には idmap_rfc2307 なら出来るという情報もちらほらあるが,少なくとも CentOS 7.6 上の Samba4.8.3 では無理なようだ。

証拠をつかもうと samba-4.8.3-4.el7 のソースを見た。すると以下のようなので,根本解決は Samba のソース改変しか無いと思われる。Workaround としては template homedir で表現可能なように,ホームディレクトリのシンボリックリンクを作成するくらいしか無いのではないか。

winbindd の getpwnam() の定義↓
source3/winbindd/winbindd.c:
           :
    578         { WINBINDD_GETPWNAM, "GETPWNAM",
    579           winbindd_getpwnam_send, winbindd_getpwnam_recv },
           :

winbindd_getpwnam_send() の中で wb_lookupname_send() のコールバックとして winbindd_getpwnam_lookupname_done() を定義↓
source3/winbindd/winbindd_getpwnam.c:

           :
     37 struct tevent_req *winbindd_getpwnam_send(TALLOC_CTX *mem_ctx,
     38                                           struct tevent_context *ev,
     39                                           struct winbindd_cli_state *cli,
           :
     80         subreq = wb_lookupname_send(state, ev,
     81                                     state->namespace,
     82                                     state->domname,
           :
     88         tevent_req_set_callback(subreq, winbindd_getpwnam_lookupname_done,
     89                                 req);
     90         return req;
     91 }
           :

winbindd_getpwnam_lookupname_done() で wb_getpwsid_send() をコール↓
source3/winbindd/winbindd_getpwnam.c:

           :
     93 static void winbindd_getpwnam_lookupname_done(struct tevent_req *subreq)
     94 {
           :
    107         subreq = wb_getpwsid_send(state, state->ev, &state->sid, &state->pw);
           :


wb_getpwsid_send() で wb_queryuser_send() をコール↓
source3/winbindd/wb_getpwsid.c:

           :
     34 struct tevent_req *wb_getpwsid_send(TALLOC_CTX *mem_ctx,
     35                                     struct tevent_context *ev,
           :
     56         subreq = wb_queryuser_send(state, ev, &state->sid);
           :


wb_queryuser_send() で wb_sids2xids_send() のコールバックとして wb_queryuser_got_uid() を定義↓
source3/winbindd/wb_queryuser.c:
           :
     39 struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx,
     40                                      struct tevent_context *ev,
     41                                      const struct dom_sid *user_sid)
     42 {
          :
     63         subreq = wb_sids2xids_send(
     64                 state, state->ev, &state->info->user_sid, 1);
     65         if (tevent_req_nomem(subreq, req)) {
     66                 return tevent_req_post(req, ev);
     67         }
     68         tevent_req_set_callback(subreq, wb_queryuser_got_uid, req);
     69         return req;
     70 }
           :

wb_queryuser_got_uid() の中では wbint_userinfo の homedir 要素に lp_template_homedir() を設定↓
source3/winbindd/wb_queryuser.c:
           :
     72 static void wb_queryuser_got_uid(struct tevent_req *subreq)
     73 {
           :
    106         info->homedir = talloc_strdup(info, lp_template_homedir());
           :
winbind においてホームディレクトリを設定しているのは上記箇所のみと思われる(見落としあったらどなたかご一報を)。 この lp_template_homedir() はおそらく source3/param/loadparm.c の以下から得られる値なので,idmap からの NSS getpwnam() や LDAP (RFC2307) homeDirectory の入る余地は無いと思われる。
source3/param/loadparm.c :
           :
    797         lpcfg_string_set(Globals.ctx, &Globals.template_homedir,
    798                          "/home/%D/%U");
           :

0 件のコメント:

コメントを投稿