0

On our file server, we are using a bunch of Linux groups that are still in use and need to be replaced by their counterparts in AD. The groups in AD and /etc/groups have an identical name, so, (I'm guessing?) chgrp won't really be of much use here.

My question is this: What's the best way of changing the group ownership of specific files on our file server to point to the groups in AD instead of the Linux groups?

I was thinking of possibly changing by GID instead of group names, but that just seems like a recipe for disaster.

0

chgrp can deal with numeric GIDs as well as symbolic group names. You'll want to be 100% sure that your name-to-name group matchup is exactly correct. Depending on how you attack the problem, it may also be necessary to ensure that the Linux numerics are in a range completely separate from the AD numerics. Most AD admins do this for obvious reasons, but check to be sure. Then you can use chgrp to remap all group ownerships, one group at a time, from the old Linux GID numbers to the new AD GID numbers. But it's critical that there is ZERO overlap between the Linux GID numbers and the AD GID numbers.

I'd suggest NOT doing the actual work in a script. Instead, write a script that just outputs a (long) string of chgrp commands. That way, if your script breaks, it doesn't harm anything. You debug the script, and then you carefully inspect the chgrp commands that it produces, and ensure they are 100% correct. Fix any bugs you identify. Once everything looks good, then pipe that list of chgrps into a shell.

As usual in UNIX (or Linux), there are more ways than one to accomplish a task. You could iterate over each group, and do one search of the file hierarchy per group. This might be okay if you don't have lots of groups, nor lots of files in the hierarchy. But it does require that the old and new numeric GIDs DO NOT overlap.

More efficient might be to search the hierarchy only once, and process all the files, one at a time, in a single pass. This also has the advantage that it does not matter whether your numerics overlap, so long as the name-to-name matchup is 100% correct. To do this, start by building a table that maps the old numeric Linux GID to the old symbolic Linux name (which is also the new symbolic AD name). Next, backup your /etc/group and edit it to delete all the Linux group names you're going to retire.

So now you have a file containing a list of GID -> name mappings, and a bunch of files in your hierarchy with a numeric GID, but no defined group name.

The next thing you'll need to do is make sure your AD group enumeration is working (through wbinfo, typically). A simple test like:

# wbinfo --group-info 'test AD group'
test AD group:x:1597:
# touch /tmp/foo
# chgrp 'test AD group' /tmp/foo
# ls -l /tmp/foo
-rw-r--r--  1 root  test AD group  0 Jun 13 11:06 /tmp/foo

should suffice. Where I have 'test AD group' you should use an AD group name that you know exists. Use quotes, just in case the group name contains spaces.

The next task at hand is to iterate over each file in the hierarchy, and use stat to find its numeric GID, which will of course be the obsolete Linux GID. Map that numeric GID to the symbolic group name (which is the new symbolic AD name), and write out a chgrp command to make that change to that file. Be sure to use quotes around the group names, because AD groups often contain spaces. Done this way, it won't matter whether your old Linux group foobar has exactly the same GID as the new AD group farkle, because your script will use the old GID, find the old name foobar and do a chgrp command to reset the group by name to be foobar.

Here's a suggestion of how to create your GID-to-name map. It's not fully tested, nor fully optimized. It's just intended to get you thinking about how to break the problem into smaller, more manageable steps. Be sure to make a full backup of your data before running any tests or final scripts.

Suppose cups cas nagios and domain users are the groups you want to migrate:

# getent group cups cas nagios "domain users" | awk -F: '{print $3 " " $1}'
193 cups
1001 cas
445 nagios
715 domain users

Save that to a file, say numeric-gid-map.txt

Now build a function that accepts a numeric GID, and returns the matching name from that file:

map_gid_to_name() {
  grep "^$1 " numeric-gid-map.txt | sed -e "s/[^ ]* //"
}

And another very simple function that will accept a group name and a file name, and output a chgrp command:

do_chgrp() {
  printf 'chgrp "%s" "%s"\n' "$1" "$2"
}

Pull those all together with one function that can take a single filename, use stat look up the numeric GID, find the corresponding group name, and write a chgrp command to stdout:

do_one_file() {
  gid=$(stat -f%g "$1")
  gname="$(map_gid_to_name $gid)"
  do_chgrp "$gname" "$1"
}

The only step left is to iterate over your hierarchy and pass the files one by one to your function.

chgrp_one_file.sh:

#!/usr/bin/env bash

map_gid_to_name() {
  grep "^$1 " numeric-gid-map.txt | sed -e "s/[^ ]* //"
}

do_chgrp() {
  printf 'chgrp "%s" "%s"\n' "$1" "$2"
}

do_one_file() {
  gid=$(stat -f%g "$1")
  gname="$(map_gid_to_name $gid)"
  do_chgrp "$gname" "$1"
}

do_one_file "$1"

chmod that 755 so it's executable.

find /your/path -print0 | xargs -0 -n1 -Ixx ./chgrp_one_file.sh "xx"

Again, I don't pretend that this is tested or optimized. It's just one possible method, that hopefully will get you started on how to improve this and bend it to suit your needs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.