+ else
+ free (gname);
+
+ free (u);
+ return _(error_msg);
+}
+
+/* Extract from SPEC, which has the form "[user][:.][group]",
+ a USERNAME, UID U, GROUPNAME, and GID G.
+ Either user or group, or both, must be present.
+ If the group is omitted but the separator is given,
+ use the given user's login group.
+ If SPEC contains a `:', then use that as the separator, ignoring
+ any `.'s. If there is no `:', but there is a `.', then first look
+ up the entire SPEC as a login name. If that look-up fails, then
+ try again interpreting the `.' as a separator.
+
+ USERNAME and GROUPNAME will be in newly malloc'd memory.
+ Either one might be NULL instead, indicating that it was not
+ given and the corresponding numeric ID was left unchanged.
+
+ Return NULL if successful, a static error message string if not. */
+
+char const *
+parse_user_spec (char const *spec, uid_t *uid, gid_t *gid,
+ char **username, char **groupname)
+{
+ char const *colon = strchr (spec, ':');
+ char const *error_msg =
+ parse_with_separator (spec, colon, uid, gid, username, groupname);