Having just implemented something that does exactly what you describe, I have one recommendation: use Text::CSV_XS. Treat the passwd, group, and shadow files as CSVs separated by ':'. Build data structures, compare then, then use the same module to output the new files.
You will save yourself a lot of hassle.
Also, don't use DATA as the name of a file handle, it's special. Also, always use strict and warnings. You'll save yourself loads of debugging time.
Ramblings and references
The Code that can be seen is not the true Code
I haven't found a problem yet that can't be solved by a well-placed trebuchet