+static int
+set_ids_by_name (struct passwd *p, struct group *g, char **message_ret)
+{
+ int uid_errno = 0;
+ int gid_errno = 0;
+ uid_t uid = p->pw_uid;
+ gid_t gid = g->gr_gid;
+
+ if (message_ret)
+ *message_ret = 0;
+
+ /* Rumor has it that some implementations of of setuid() do nothing
+ when called with -1; therefore, if the "nobody" user has a uid of
+ -1, then that would be Really Bad. Rumor further has it that such
+ systems really ought to be using -2 for "nobody", since that works.
+ So, if we get a uid (or gid, for good measure) of -1, switch to -2
+ instead.
+ */
+ if (gid == (gid_t) -1) gid = (gid_t) -2;
+ if (uid == (uid_t) -1) uid = (uid_t) -2;
+
+ errno = 0;
+ if (setgid (gid) != 0)
+ gid_errno = errno ? errno : -1;
+
+ errno = 0;
+ if (setuid (uid) != 0)
+ uid_errno = errno ? errno : -1;
+
+ if (uid_errno == 0 && gid_errno == 0)
+ {
+ static char buf [1024];
+ sprintf (buf, "changed uid/gid to %s/%s (%ld/%ld).",
+ p->pw_name, (g ? g->gr_name : "???"),
+ (long) uid, (long) gid);
+ if (message_ret)
+ *message_ret = buf;
+ return 0;
+ }
+ else
+ {
+ char buf [1024];
+ if (gid_errno)
+ {
+ sprintf (buf, "%s: couldn't set gid to %s (%ld)",
+ blurb(),
+ (g ? g->gr_name : "???"),
+ (long) gid);
+ if (gid_errno == -1)
+ fprintf(stderr, "%s: unknown error\n", buf);
+ else
+ perror(buf);
+ }
+
+ if (uid_errno)
+ {
+ sprintf (buf, "%s: couldn't set uid to %s (%ld)",
+ blurb(),
+ (p ? p->pw_name : "???"),
+ (long) uid);
+ if (uid_errno == -1)
+ fprintf(stderr, "%s: unknown error\n", buf);
+ else
+ perror(buf);
+ }
+
+ return -1;
+ }
+}
+
+static int
+set_ids_by_number (uid_t uid, gid_t gid, char **message_ret)
+{
+ struct passwd *p;
+ struct group *g;
+
+ errno = 0;
+ p = getpwuid (uid);
+ if (!p)
+ {
+ char buf [1024];
+ sprintf (buf, "%s: error looking up name of user %d", blurb(),
+ (long) uid);
+ if (errno)
+ perror (buf);
+ else
+ fprintf (stderr, "%s: unknown error.\n", buf);
+ return -1;
+ }
+
+ errno = 0;
+ g = getgrgid (gid);
+ if (!g)
+ {
+ char buf [1024];
+ sprintf (buf, "%s: error looking up name of group %d", blurb(),
+ (long) gid);
+ if (errno)
+ perror (buf);
+ else
+ fprintf (stderr, "%s: unknown error.\n", buf);
+ return -1;
+ }
+
+ return set_ids_by_name (p, g, message_ret);
+}
+
+