查询用户uid和gid_在AIX上标准化用户UID和GID号

在具有多个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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值