查询用户uid和gid

    技术2024-05-31  116

    在具有多个AIX系统的环境中,通常在不同系统之间的UID(用户ID)和GID(组ID)编号不一致。 由于多种原因,这可能是有问题的,并且是一个值得解决的问题。 本文介绍了AIX上的UID和GID号以及在多个服务器之间存在上述不一致的一些具体问题。 还将解决在AIX上手动更改UID和GID号以创建一致性的问题,以及可以自动执行任务以大规模标准化UID和GID的脚本。

    AIX中的UID和GID编号概述

    在诸如AIX之类的UNIX系统上,操作系统代表具有UID编号的用户和代表GID编号的组。 您可以通过运行id命令轻松地在AIX帐户上查看您的UID和GID号。

    清单1. id输出
    $ id uid=404(brian) gid=402(testgroup) groups=1(staff)

    在上面的清单1中 ,您可以看到brian帐户的UID号是404。该用户还具有一个GID为402的主要组(测试组),并且也是GID 1的一个成员(职员)。

    磁盘上存储的每个文件都有一个所有者和一个组,但是用户和组的实际名称未存储在磁盘上。 而是存储代表用户和组的UID和GID号。 您可以通过在文件上运行istat命令来查看此信息。

    清单2. 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

    在上面的清单2中 ,您可以看到文件的所有者是UID 404(布莱恩),组是402(testgroup)。

    系统上的其他项目(例如包含正在运行的进程的进程表)通过跟踪UID和GID号而不是实际使用用户名和组名来跟踪谁拥有该进程。

    问题

    如果您有多台服务器,则UID和GID号在服务器之间可能不一致。 默认情况下,当您在AIX中创建用户或组时,它只是为其分配下一个可用的UID或GID号。 如果您的环境中有多台服务器,则服务器之间的UID和GID号可能会很快变得不一致。 这意味着“布莱恩”用户在Server1上的UID为404,在Server2上的UID为406,在Server3上的UID为402。

    这可能有两个原因。 在所有服务器上统一一致的UID和GID号的最大原因之一是,您可以移至中央身份验证系统,例如LDAP。 中央认证系统(例如LDAP)通常要求启用LDAP的用户和组在所有LDAP连接的服务器上具有一致的UID和GID。

    即使您不希望使用诸如LDAP之类的中央身份验证,您仍然会遇到UID和GID编号不一致的问题。 例如,假设您有一个映射到ServerA的SAN LUN。 该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”作为所有者。

    在服务器之间导出NFS共享时,服务器之间的UID / GID编号不一致也可能会引起问题。

    手动更改GID和UID号的步骤

    在此示例中,您将为用户(布莱恩)更改单个UID,为组(测试组)更改GID。 “布莱恩”用户的原始UID为404,新的UID将为3504。“测试组”将原始GID分组为402,新的GID将为5001。更改GID或UID号是一个多步骤过程。

    步骤1.停止应用程序并让用户注销

    在更改GID或UID编号之前,重要的是停止所有正在运行的应用程序并使所有用户注销服务器。 进程表根据UID和GID编号跟踪正在运行的进程。 因此,如果在更改这些数字的同时用户正在运行进程,则会发生无法预测的结果。 同样,在以后的步骤中确定文件所有权之前,用户将暂时失去对其文件的访问权限。

    步骤2.查找以该组为主要组的用户

    系统上的每个用户都有一个在/ etc / passwd文件中定义的主要组。 当您在步骤3中更改GID编号时,AIX会显示一条警告消息,指出它不会使用新的GID更新/ etc / passwd文件。 因此,在更改GID之前,首先要获得将要更改的组作为其主要组的所有用户的列表。 可能没有任何用户以此为主要组,或者可能有多个用户。 要找出答案,请运行下面清单3中的命令:

    清单3. lsuser输出
    # lsuser -a pgrp ALL | grep pgrp=testgroup brian pgrp=testgroup

    此命令显示系统上有一个以testgroup为主要用户的用户(布莱恩)。 记录此命令显示的用户,因为您需要在以后的步骤中运行命令来修复它们。

    步骤3.更改GID号

    使用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中收集了这些用户的列表,然后在下一步中将解决此问题。

    步骤4.修复用户主要组

    对于在步骤2中记下的每个用户,运行以下命令来修复其主要组。 请注意,可能没有任何用户将该组作为其主要组,或者可能有多个用户。

    清单5. chuser命令更新主组
    # chuser pgrp=testgroup brian

    此chuser命令使用测试组的新GID号为brian用户更新/ etc / passwd文件。

    步骤5.更改UID号

    使用chuser命令将用户brian的UID更改为UID 3504(最初是404)。

    清单6.更改UID的chuser命令
    # chuser id=3504 brian

    此时,系统上已更改了brian UID和测试组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号存储在每个文件上,而不是存储用户名或组名。 在下一步中,您将解决此问题。

    步骤6.修复系统上所有文件的用户和组所有权

    在此步骤中,您将修复系统上所有文件的用户和组所有权。 这是通过运行两个查找命令来完成的,这些命令搜索具有先前UID和GID的所有文件。 对于找到的满足这些条件之一的每个文件,将使用新的用户和组所有权更新文件。

    清单9.查找修复所有权的命令
    # find / -group 402 -exec chgrp -h testgroup {} \; # find / -user 404 -exec chown -h brian {} \;

    完成这些命令后,将更正系统上所有针对testgroup组和brian用户的文件的用户和组所有权。 如果在brian用户的主目录上运行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和GID标准化为uid.txt和gid.txt输入文件中列出的新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将不再在输出中列出。

    清单13. fix_gid_uid.pl脚本
    #!/usr/bin/perl # This is unsupported code. This script is provided "as is" without warranty of # any kind, expressed or implied, including, but not limited to, the implied # warranty of merchantability or fitness for a particular purpose. # Use at your own risk. # use Getopt::Long; use User::pwent; use User::grent; my ($uid_file, $gid_file); GetOptions("uidfile=s" => \$uid_file, "gidfile=s" => \$gid_file); if (!((defined $gid_file) || (defined $uid_file))){ print "Specify at least one arguments: --uidfile <filename> "; print "AND/OR --gidfile <filename>\n\n"; print "Example: $0 --uidfile uid.txt --gidfile gid.txt\n\n"; print "Format of UID and GID files should be: \n"; print "<Desired GID/UID#> <User/Group Name>\n\n"; print "Example:\n"; print "3000 user1\n"; print "3001 user2\n\n"; exit 1; } if (defined $gid_file){ open GIDFILE, "<$gid_file" or die $!; while (<GIDFILE>){ my $line = $_; if ($line =~ /(\S+)\s+(\S+)\s*/){ my $gid = $1; my $group = $2; while($ent = getgrent()){ my $ent_name = $ent->name; my $ent_gid = $ent->gid; if ($ent_gid == $gid){ if ($ent_name ne $group){ print "### Error, Group in $gid_file file ($group, GID: $gid)"; print " conflicts with group on system ($ent_name, GID: $ent_gid)\n"; print "### Exiting program, please fix and rerun\n"; exit 2; } } } endgrent(); } } close GIDFILE; } if (defined $uid_file){ open UIDFILE, "<$uid_file" or die $!; while (<UIDFILE>){ my $line = $_; if ($line =~ /(\S+)\s+(\S+)\s*/){ my $uid = $1; my $name = $2; while($ent = getpwent()){ my $ent_name = $ent->name; my $ent_uid = $ent->uid; if ($ent_uid == $uid){ if ($ent_name ne $name){ print "### Error, User in $uid_file file ($name, UID: $uid)"; print "conflicts with user on system ($ent_name, UID: $ent_uid)\n"; print "### Exiting program, please fix and rerun\n"; exit 2; } } } endpwent(); } } close UIDFILE; } if (defined $gid_file){ print "\n### Commands to update Groups ###\n\n"; open GIDFILE, "<$gid_file" or die $!; while (<GIDFILE>){ my $line = $_; chomp($line); if ($line =~ /(\S+)\s+(\S+)\s*/){ my $newgid = $1; my $group = $2; my $return = system("lsgroup $group >/dev/null 2>&1"); if ($return == 0) { my $oldgid = `lsgroup -a id $group | cut -f 2 -d =`; chomp($oldgid); if ($oldgid != $newgid){ print "chgroup id=$newgid $group\n"; while($ent = getpwent()){ my $ent_user = $ent->name; my $ent_gid = $ent->gid; if ($ent_gid == $oldgid){ print "chuser pgrp=$group $ent_user \n"; } } endpwent(); print "find / -group $oldgid -exec chgrp -h $group {} \\;\n"; } } } } close GIDFILE; } if (defined $uid_file){ print "\n### Commands to update Users ###\n\n"; open UIDFILE, "<$uid_file" or die $!; while (<UIDFILE>){ my $line = $_; chomp($line); if ($line =~ /(\S+)\s+(\S+)\s*/){ my $newuid = $1; my $user = $2; my $return = system("lsuser $user >/dev/null 2>&1"); if ($return == 0) { my $olduid = `lsuser -a id $user | cut -f 2 -d =`; chomp($olduid); if ($olduid != $newuid){ print "chuser id=$newuid $user\n"; print "find / -user $olduid -exec chown -h $user {} \\;\n"; } } } } close UIDFILE; }

    结论

    跨多个AIX服务器具有一致的UID和GID号被认为是最佳实践,并且如本文所证明,这是可以实现的目标。 通过遵循本文中概述的过程,系统管理员可能会通过标准化UID和GID编号来防止将来发生问题。


    翻译自: https://www.ibm.com/developerworks/aix/library/au-standardUID/index.html

    Processed: 0.014, SQL: 9