1. 記事一覧 >
  2. ブログ記事
Unix/Linux
category logo

rsyncで名前が一致してもowner,groupを引き継がなかった件

(更新) (公開)

はじめに

あるとき、コピー元でrsyncをデーモン起動して、コピー先でrsyncクライアントを実行してファイルをコピーしていると、owner,groupが引き継がれていないのに気付きました。よく見ると、nobody(65534):wheel(0)→nfsnobody(65534):root(0)と名前の一致ではなく、id番号のみで引き継がれていました。-a オプションなので、名前、id番号で引き継ぐはずです。(名前が一致しなかったら、id番号)
これは、なぜなのか、解決する方法は無いのか、探ってみました。

まとめ

いきなりまとめを書きますと、rsyncのowner,groupの引継ぎで名前とidがズレる件に関して、2点重要な事実がありました。


rsyncd.confにuse chroot=trueが設定されている場合、名前の一致は見ない。
 例:nobody(65534)→nfsnobody(65534)
 これを回避するためには、use chroot=falseとするかname converter = nameconvertと設定し、name converterを利用する必要がある。


id=0のowner,groupの場合、名前は無視されて、必ずrsync先でもid=0になる。
 例:wheel(0)→root(0)になる。wheel(0)→wheel(10)とはならない。
 これを回避するためには、--groupmap=0:wheelオプションを付与するか、rsyncのソースコードの書き換えが必要。


以降、検証していきます。


【検証環境】

FreeBSD 12.2-RELEASE

 rsync version 3.2.3 protocol version 31

CentOS Linux release 7.6.1810

 rsync version 3.2.3 protocol version 31


nobody(65534)→nfsnobody(65534)

●FreeBSD側(コピー元)
テストデータを作ります。

# mkdir -p /usr/aaa/bbb/ccc
# vi /usr/aaa/bbb/ccc/test.txt
# chown -R nobody:wheel /usr/aaa
# find /usr/aaa -ls
10977537        8 drwxr-xr-x    3 nobody    wheel    512 Oct 29 22:42 /usr/aaa
10977538        8 drwxr-xr-x    3 nobody    wheel    512 Oct 29 22:42 /usr/aaa/bbb
10977539        8 drwxr-xr-x    2 nobody    wheel    512 Oct 29 22:42 /usr/aaa/bbb/ccc
10977540        8 -rw-r--r--    1 nobody    wheel      5 Oct 29 22:42 /usr/aaa/bbb/ccc/test.txt

rsyncd.confを作成します。

# vi /etc/rsyncd.conf
uid = root
gid = wheel
use chroot = true
hosts allow = *
hosts deny = *
[TEST]
path = /usr/aaa/
read only = true

rsyncd.confの詳しい解説は省略します。

ここで要注目なのは、use chroot = trueを設定していることです。


rsyncをデーモンモードで起動します。

# /usr/local/bin/rsync --daemon --config /etc/rsyncd.conf

●CentOS側(コピー先)

rsyncを起動します。

# /usr/local/bin/rsync -acv 192.168.12.212::TEST /usr/aaa

192.168.12.212は、FreeBSD側(コピー元)のIPアドレスです。

rsyncコマンドの詳しい解説は省略します。

今回、デーモン側がFreeBSDのため、特に何もしていませんでしたが、CentOSがデーモン側の場合、以下の処置が必要かもしれません。

setsebool -P rsync_full_access on

firewall-cmd --add-service=rsyncd --permanent

firewall-cmd --reload


確認します。

# find /usr/aaa -ls
67160578    0 drwxr-xr-x   3 nfsnobody root           17 10月 29 22:42 /usr/aaa
100663408    0 drwxr-xr-x   3 nfsnobody root           17 10月 29 22:42 /usr/aaa/bbb
   651    0 drwxr-xr-x   2 nfsnobody root           22 10月 29 22:42 /usr/aaa/bbb/ccc
146733    4 -rw-r--r--   1 nfsnobody root            5 10月 29 22:42 /usr/aaa/bbb/ccc/test.txt

use chroot = trueのため、
nobody(65534)→nfsnobody(65534)
になっています。


nobody(65534)→nobody(99) その1

●FreeBSD側(コピー元)

use chroot = false
にします。

# vi /etc/rsyncd.conf

※rsyncデーモンの再起動は不要です。

uid = root
gid = wheel
use chroot = false
hosts allow = *
hosts deny = *
[TEST]
path = /usr/aaa/
read only = true

●CentOS側(コピー先)

rsyncを起動します。

# rm -rf /usr/aaa
# /usr/local/bin/rsync -acv 192.168.12.212::TEST /usr/aaa
receiving incremental file list
created directory /usr/aaa
./
bbb/
bbb/ccc/
bbb/ccc/test.txt

sent 58 bytes  received 207 bytes  176.67 bytes/sec
total size is 5  speedup is 0.02
# find /usr/aaa
/usr/aaa
/usr/aaa/bbb
/usr/aaa/bbb/ccc
/usr/aaa/bbb/ccc/test.txt
# find /usr/aaa -ls
34747680    0 drwxr-xr-x   3 nobody   root           17 10月 29 22:42 /usr/aaa
67160578    0 drwxr-xr-x   3 nobody   root           17 10月 29 22:42 /usr/aaa/bbb
100663408    0 drwxr-xr-x   2 nobody   root           22 10月 29 22:42 /usr/aaa/bbb/ccc
100663766    4 -rw-r--r--   1 nobody   root            5 10月 29 22:42 /usr/aaa/bbb/ccc/test.txt

nobody(65534)→nobody(99)になりました!


nobody(65534)→nobody(99) その2

# man rsyncd.conf

のuse chrootのところを見ると、use chrootを有効にすると、"name converter"が無効になり、"numeric ids"がデフォルトになると書かれています。

use chroot
       If "use chroot" is true, the rsync daemon will chroot to the
・・・(略)・・・
       When this parameter is enabled and the "name converter"
       parameter is not set, the "numeric ids" parameter will default
       to being enabled (disabling name lookups).  This means that if
       you manually setup name-lookup libraries in your chroot (instead
       of using a name converter) that you need to explicitly set
       numeric ids = false for rsync to do name lookups.

さらに、name converterの項目には、以下のように書かれています。
「owner,groupのname,idをいじれる任意のプログラムを指定できる。"nameconvert"というサンプルプログラムが有るから、それ見てカスタマイズの自由を感じるんだ。」

name converter
       This parameter lets you specify a program that will be run by
       the rsync daemon to do user & group conversions between names &
       ids.  This script is started prior to any chroot being setup,
       and runs as the daemon user (not the transfer user).  You can
       specify a fully qualified pathname or a program name that is on
       the $PATH.
・・・(略)・・・
       There is a sample python script in the support dir named
       "nameconvert" that implements the normal user & group lookups.
       Feel free to customize it or just use it as documentation to
       implement your own.

ソースコードを探したら、有りました。

# find rsync-3.2.3 -name nameconvert
rsync-3.2.3/support/nameconvert

python3で書かれています。

#!/usr/bin/env python3

# This implements a simple protocol to do user & group conversions between
# names & ids.  All input and output consists of simple strings with a
# terminating newline.
#
# The requests can be:
#
#   uid ID_NUM\n  ->  NAME\n
#   gid ID_NUM\n  ->  NAME\n
#   usr NAME\n    ->  ID_NUM\n
#   grp NAME\n    ->  ID_NUM\n
#
# An unknown ID_NUM or NAME results in an empty return value.
#
# This is used by an rsync daemon when configured with the "name converter" and
# (often) "use chroot = true".  While this converter uses real user & group
# lookups you could change it to use any mapping idiom you'd like.

import sys, argparse, pwd, grp

def main():
    for line in sys.stdin:
        try:
            req, arg = line.rstrip().split(' ', 1)
        except:
            req = None
        try:
            if req == 'uid':
                ans = pwd.getpwuid(int(arg)).pw_name
            elif req == 'gid':
                ans = grp.getgrgid(int(arg)).gr_name
            elif req == 'usr':
                ans = pwd.getpwnam(arg).pw_uid
            elif req == 'grp':
                ans = grp.getgrnam(arg).gr_gid
            else:
                print("Invalid request", file=sys.stderr)
                sys.exit(1)
        except KeyError:
            ans = ''
        print(ans, flush=True)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Convert users & groups between names & numbers for an rsync daemon.")
    args = parser.parse_args()
    main()

python3をインストールして、nameconvertをパスが通るところに置いて、name converter = nameconvertを設定してみます。
普通に実行すると、owner,groupの名前を引き継がないuse chroot = trueとします。

# pkg install python3
# cp -p rsync-3.2.3/support/nameconvert /usr/local/bin/
# vi /etc/rsyncd.conf
uid = root
gid = wheel
use chroot = true
name converter = nameconvert
hosts allow = *
hosts deny = *
[TEST]
path = /usr/aaa/
read only = true
# find /usr/aaa
/usr/aaa
/usr/aaa/bbb
/usr/aaa/bbb/ccc
/usr/aaa/bbb/ccc/test.txt
# find /usr/aaa -ls
34747680    0 drwxr-xr-x   3 nobody   root           17 10月 29 22:42 /usr/aaa
67160578    0 drwxr-xr-x   3 nobody   root           17 10月 29 22:42 /usr/aaa/bbb
100663408    0 drwxr-xr-x   2 nobody   root           22 10月 29 22:42 /usr/aaa/bbb/ccc
100663766    4 -rw-r--r--   1 nobody   root            5 10月 29 22:42 /usr/aaa/bbb/ccc/test.txt

nobody(65534)→nobody(99)になりました!


wheel(0)→root(0)

use chroot=falseとするかname converter = nameconvertとname converterを利用した場合、owner,groupの名前が引き継がれますが、それでもnobody:wheel→nobody:rootとなってしまいます。他の例えば、admin:adminは、idが違っていても、コピー先はadmin:adminで付与されます。
なぜ、 nobody:wheel→nobody:root になってしまうのか不思議に思い、ソースコードを調べてみました。


# /usr/local/bin/rsync -acv --debug=OWN2 192.168.12.212::TEST /usr/aaa

のように実行してみた結果、

uid 65534(nobody) maps to 99
gid 0(wheel) maps to 0

と出力があり、"maps to"でgrepをかけて、uidlist.cに以下のコードを見つけました。

if (node)
        id2 = node->id2;
else if (*name && id) {
        if (idlist_ptr == &uidlist) {
                uid_t uid;
                id2 = user_to_uid(name, &uid, False) ? uid : id;
        } else {
                gid_t gid;
                id2 = group_to_gid(name, &gid, False) ? gid : id;
        }
} else
        id2 = id;

*name && idのところで、wheelの場合、id=0になっています。id=0の場合、elseの方へ行ってしまうので、照合対象には、nameではなく、idが入ります。


CentOS側でuidlist.cを以下のように変更して、再make、再実行します。

else if (*name && id) {

else if (*name) {

# make clean
# make
# make install
# /usr/local/bin/rsync -acv --debug=OWN2 192.168.12.212::TEST /usr/aaa
receiving incremental file list
uid 65534(nobody) maps to 99
gid 0(wheel) maps to 10
created directory /usr/aaa
set uid of . from 0 to 99
set gid of . from 0 to 10
./
set uid of bbb from 0 to 99
set gid of bbb from 0 to 10
set uid of bbb/ccc from 0 to 99
set gid of bbb/ccc from 0 to 10
bbb/
bbb/ccc/
bbb/ccc/test.txt
set uid of bbb/ccc/.test.txt.nMoiTu from 0 to 99
set gid of bbb/ccc/.test.txt.nMoiTu from 0 to 10

sent 58 bytes  received 210 bytes  536.00 bytes/sec
total size is 5  speedup is 0.02
# find /usr/aaa -ls
100664533    0 drwxr-xr-x   3 nobody   wheel          17 10月 29 22:42 /usr/aaa
   691    0 drwxr-xr-x   3 nobody   wheel          17 10月 29 22:42 /usr/aaa/bbb
34747680    0 drwxr-xr-x   2 nobody   wheel          22 10月 29 22:42 /usr/aaa/bbb/ccc
34747681    4 -rw-r--r--   1 nobody   wheel           5 10月 29 22:42 /usr/aaa/bbb/ccc/test.txt

wheel(0)→wheel(10)になりました!
ヨシ!

今回強引に通してやってみただけで、何らかの問題が生じても、一切責任を負いません。


wheel(0)→wheel(10)

上記の場合、ソースコードを書き換えて対応しましたが、wheel(0)→wheel(10)を実現する方法として、より簡単な方法がありました。
--groupmap=0:wheelオプションの付与です。
gid=0の場合、"wheel"でchgrpするという意味です。
0は、名前でも良く、--groupmap=admin:wheelのように使えます。
ownerの方は、--usermap=pgsql:postgresのように使えます。
また、カンマ区切りで複数指定できます。
--groupmap=pgsql:postgres,0:wheel
注意:--groupmap=pgsql:postgres --groupmap=0:wheelはエラーになります。


CentOS側でソースコードをオリジナルに戻して、--groupmap=0:wheelオプションを付与して実行してみます。

# /usr/local/bin/rsync -acv --groupmap=0:wheel --debug=OWN2 192.168.12.212::TEST /usr/aaa
receiving incremental file list
uid 65534(nobody) maps to 99
gid 0(wheel) maps to 10
created directory /usr/aaa
set uid of . from 0 to 99
set gid of . from 0 to 10
./
set uid of bbb from 0 to 99
set gid of bbb from 0 to 10
set uid of bbb/ccc from 0 to 99
set gid of bbb/ccc from 0 to 10
bbb/
bbb/ccc/
bbb/ccc/test.txt
set uid of bbb/ccc/.test.txt.tCFeAV from 0 to 99
set gid of bbb/ccc/.test.txt.tCFeAV from 0 to 10

sent 58 bytes  received 210 bytes  536.00 bytes/sec
total size is 5  speedup is 0.02
# find /usr/aaa -ls
34747680    0 drwxr-xr-x   3 nobody   wheel          17 10月 29 22:42 /usr/aaa
67160578    0 drwxr-xr-x   3 nobody   wheel          17 10月 29 22:42 /usr/aaa/bbb
100664536    0 drwxr-xr-x   2 nobody   wheel          22 10月 29 22:42 /usr/aaa/bbb/ccc
100664538    4 -rw-r--r--   1 nobody   wheel           5 10月 29 22:42 /usr/aaa/bbb/ccc/test.txt

ヨシ!


loading...