在拥有多个 AIX 系统的环境中,不同系统中的 UID (User ID) 和 GID (Group ID) 编号不一致是常见现象。有几个原因会造成此问题,这是一个值得解决的问题。本文讲解了 AIX 上的 UID 和 GID 编号究竟是什么,以及前面提到的多个服务器上的编号不一致会造成的几个具体问题。本文还将介绍如何手动修改 AIX 上的 UID 和 GID 编号使其一致,并且创建一个大规模标准化 UID 和 GID 的脚本。
在例如 AIX 这样的 UNIX 系统上,操作系统用 UID 编号表示用户,用 GID 编号表示组。您可以很容易地通过运行 id
命令来查看 AIX 帐户上的 UID 和 GID 编号。
$ id uid=404(brian) gid=402(testgroup) groups=1(staff) |
在以上的清单 中,您会看到 brian 账户的 UID 编号是 404。用户有一个 GID 为 402 的主要组(testgroup),而且是 GID 1(staff)的成员。
存储在磁盘上的每个文件都有一个所有者和一个组,尽管用户和组的实际名称不存储在磁盘上。存储的是表示用户和组的 UID 和 GID 编号。您可以通过运行文件上的istat
命令来查看。
$ istat testfile Inode 131073 on device 10/5 File Protection: rwxr----- Owner:404(brian) Group:402(testgroup) Link count: 1 Length 291 bytes Last updated: Tue Apr 8 09:04:17 MDT 2008 Last modified:Wed Feb 7 13:22:36 MST 2007 Last accessed:Thu Sep 30 12:36:59 MDT 2010 |
在以上的 清单 中,您会看到文件的所有者是 UID 404 (brian),组是 402 (testgroup)。
系统中的其他条目,比如包含正在运行进程的进程表,它通过追踪 UID 和 GID 编号而不是实际的用户名和组名来追踪谁拥有这些进程
问题
如果您有多个服务器,那么这多个服务器之间的 UID 和 GID 编号可能不一致。默认情况下在 AIX 中创建用户或组时,它只是分配下一个可用的 UID 或 GID 编号。如果环境中有一个或多个服务器,服务器之间的 UID 和 GID 会很快变得不一致。这意味着 “brian” 用户可能在 Server1 上的 UID 为 404,Server2 上 的 UID 为 406,Server3 上的 UID 为 402。 |
有几个原因会造成此问题。将所有服务器上的 UID 和 GID 编号都一致地标准化的最大原因是您可以迁移到一个集中认证系统,如 LDAP。LDAP 等集中认证系统通常要求通过 LDAP 连接的所有服务器上启用 LDAP 的用户和组具有一致的 UID 和 GID。
即使您不想使用集中认证,如 LDAP,您还是会遇到 UID 和 GID 不一致的问题。例如,如果有一个 SAN LUN 映射到 ServerA。可能有上千个文件存储在 LUN 上。存储在 LUN 上的每个文件都有一个文件所有者和一个组,保存为 UID 和 GID 编号。因此如果使用此 LUN,断开它与 ServerA 的映射,并且让它映射到 ServerB,那么如果 ServerA 与 ServerB 之间 的 UID 和 GID 不一致,就会造成问题。在此场景中,可能会有几个问题。如果用户 brian 在 ServerA 上的 UID 是 404,用户 bob 在 ServerB 上的 UID 是 404,在转移 LUN 之后,用户 bob 就会拥有用户 brian 的所有文件。如果 ServerB 上没有 UID 404,那么 ServerB 上的文件就没有所有者,那么在运行ls –al
命令时只能看到 “404” 作为所有者。
当在服务器之间导出 NTF 共享时,服务器之间 UID/GID 编号不一致也会造成问题。
本例中,您将更改用户(brian)的 UID 和组(testgroup)的 GID。“brian” 用户原有的 UID 是 404,新的 UID 是 3504。“testgroup” 组原有的 GID 是 402,新的 GID 是 5001。更改 GID 或 UID 编号分为多个步骤。
在更改 GID 或 UID 编号之前,停止所有正在运行的应用程序并且让所有用户从服务器注销很重要。进程表会根据 UID 和 GID 编号跟踪正在运行的进程。因此,如果进程运行时更改这些编号,会产生无法预料的结果。还有,在下一步修复文件所有权之前,用户会暂时无法访问文件。
系统中的每个用户都有一个在 /etc/passwd 文件中定义的主要组。在步骤 3 中更改 GID 编号时,AIX 会打印出它未用新的 GID 更新 /etc/passwd 文件的警告消息。因此,在更改 GID 之前,首先要获取所有将您正更改的组作为主要组的用户清单。可能没有一个用户将其作为主要组,或者可能有多个用户。要将其找出,运行以下清单 3 所示的命令:
清单 3. lsuser 输出
# lsuser -a pgrp ALL | grep pgrp=testgroup brian pgrp=testgroup |
此命令显示系统中有一个用户(brian)将 testgroup 作为主要组。记下此命令显示的用户,因为您需要在以后的步骤中运行命令来修复它们。
使用 chgroup
命令将 testgroup 的 GID 改成 5001(原先 GID 是 402)。
清单 4. chgroup 输出
# chgroup id=5001 testgroup 3004-719 Warning:/usr/bin/chgroup does not update /etc/passwd with the new gid. |
chgroup 打印出警告消息让您知道它未用新的 GID 更新 /etc/passwd。此警告适用于所有将组作为主要组的用户。您在步骤 2 中收集了这些用户的列表,将在下一步中修复。
对于步骤 2 中的所有表,运行以下的命令修复其主要组。注意,可能没有一个用户将其作为主要组,或者可能有多个用户。
清单 5. chuser 命令更新主要组
# chuser pgrp=testgroup brian |
chuser
命令会用 testgroup 的新 GID 编号更新 /etc/passwd 文件中的 brian 用户。
使用 chuser
命令将用户 brian 的 UID 改成 3504 (原先是 404)。
清单 6. chuser 命令更改 UID
# chuser id=3504 brian |
此时,系统上 brian 的 UID 和 testgroup 的 GID 都已改变。您可以运行 id brian
命令来查看新的 UID 和 GID。
清单 7. id brian 输出
# id brian uid=3504(brian) gid=5001(testgroup) groups=1(staff) |
此时还未完成。如果在用户主目录运行 ls –al
命令,您很快会看到问题。
清单 8. 用户主目录的 ls 输出
# ls -al /home/brian drwxr-xr-x 5 404 402 4096 2009-04-08 09:12 . drwxr-xr-x 10 bin bin 256 2007-03-01 15:06 .. -rw-r--r-- 1 404 402 10 2007-02-07 13:22 .kshrc -rwxr----- 1 404 402 291 2007-02-07 13:22 .profile -rw------- 1 404 402 438 2010-11-10 11:40 .sh_history |
如您所见,用户和组都正常显示,您只看到之前显示的 UID 和 GID 编号(404 和 402)。如果用户 brian 登录到系统,他将不会是这些文件的所有者。这是因为系统在每个文件中存储的是所有者和组的 UID 和 GID 编号,而不是用户或组名称。下一步将会修复此问题。
在这一步中,将会修复系统中所有文件的用户和组所有权。这是通过运行两个 find 命令来完成的,它们会查找具有之前的 UID 和 GID 的所有文件。对于每个符合以上标准之一的文件,都会用新的用户和组所有权来更新。
清单 9. find 命令修复所有权
# find / -group 402 -exec chgrp -h testgroup {} \; # find / -user 404 -exec chown -h brian {} \; |
这些命令一旦完成,系统上所有文件的 testgroup 组和 brian 用户的用户和组所有权都会被更正过来。如果在 brain 用户的主目录运行 ls –al
命令,您可以得到确认。
之前的步骤需要花费大量时间来完成,而且只能更改一个用户和组的 UID 和 GID。如果您的环境中有多个 AIX 服务器,而且每个服务器都有多个用户和组,那么显然手动更改所有 UID 和 GID 是不切实际的。
我写了一个 Perl 脚本来自动化此过程。提供给脚本两个输入文件:包含已更新的 UID 信息的文件,以及包含已更新的 GID 信息的文件。
在 UID 文件中,每行列出两列信息。第一列是要设置的新 UID,第二列是帐户名称。GID 文件也类似。第一列是要设置的新 GID,第二列是组名称。
以下的清单 10 显示了文件内容。
清单 10. UID 和 GID 文件的内容
# cat uid.txt 3500 megan 3501 todd 3502 app_user # # cat gid.txt 5000 app_group |
如果脚本在 UID 或 GID 文件中找到的用户或组在系统中不存在,那就跳过该行。这使得创建所有系统中的所有用户和组的列表变得非常容易,并且可以创建一个单独的 UID 和 GID 文件,用来标准化所有系统上的 UID 和 GID,即使每个系统上都没有相同的用户或组。还有,如果脚本运行时检测到系统上用户或组的当前的 UID 或 GID 与输入文件中要求的 UID/GID 一样,那么它会跳过这些行。这样就可以在即使已具有已经标准化的 UID 和 GID 的用户帐户的系统上使用输入文件的主 UID/GID 列表来运行脚本。
当脚本运行时,它不会改变系统上所有内容;它只会从系统中收集用户和组信息并在屏幕上显示标准化 UID 和 GID 编号所需的命令。
要运行此脚本,使用类似下面清单 11 中的命令。
清单 11. 运行 fix_gid_uid.pl 脚本
# ./fix_gid_uid.pl --uidfile uid.txt --gidfile gid.txt ### Commands to update Groups ### chgroup id=5000 app_group chuser pgrp=app_group todd chuser pgrp=app_group megan chuser pgrp=app_group app_user chuser pgrp=app_group app_2 chuser pgrp=app_group app_3 chuser pgrp=app_group app_4 find / -group 14 -exec chgrp -h app_group {} \; ### Commands to update Users ### chuser id=3500 megan find / -user 406 -exec chown -h megan {} \; chuser id=3501 todd find / -user 402 -exec chown -h todd {} \; chuser id=3502 app_user find / -user 409 -exec chown -h app_user {} \; |
脚本在屏幕上显示出按照 uid.txt 和 gid.txt 输入文件中列出的新 UID 和 GID 标准化该系统上的 UID 和 GID 所需的所有命令。
请注意,输出结果显示,有六个用户需要在 app_group 组的 GID 改变后改变其主要组。这包含了 uid.txt 文件中未包含的用户。原因是一旦 GID 组改变,所有将该组作为主要组的用户都需要将主要组更新,即使这些用户未改变 UID。
一旦运行脚本并确认输出结果正确,运行命令就简单了。为此,再次运行脚本,并将输出结果重定向到文件中。让输出文件可执行,然后运行。
清单 12. 对系统作出实际更改
# ./fix_gid_uid.pl --uidfile uid.txt --gidfile gid.txt > commands # chmod +x commands # ./commands |
运行时间取决于系统中有多少组和用户被修改,以及有多少文件。根据这些因素,时间范围可能从一分钟到超过一小时。如果您担心运行时间,可以将命令文件分成几部分,分别执行。如果维护时段快要结束,您可以完成当前部分。如果有了另外一个维护时段,只需再次运行 fix_gid_uid.pl 脚本。它会生成需要运行的新命令,而之前已经修复的 UID 和 GID 将不会再次出现在输出结果中。
结束语
让多个 AIX 服务器上的 UID 和 GID 保持一致被视为是一种最佳实践,而且如本文所示,这是一个可以实现的目标。按照本文所列的流程操作,系统管理员可以避免在标准化 UID 和 GID 编号过程中可能出现的问题。