- 記事一覧 >
- ブログ記事
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
ヨシ!
その他、宣伝、誹謗中傷等、当方が不適切と判断した書き込みは、理由の如何を問わず、投稿者に断りなく削除します。
書き込み内容について、一切の責任を負いません。
このコメント機能は、予告無く廃止する可能性があります。ご了承ください。
コメントの削除をご依頼の場合はTwitterのDM等でご連絡ください。