+ /* --- Fiddle with group ownerships a bit --- */
+
+ {
+#ifdef HAVE_SETGROUPS
+ gid_t from_gr[NGROUPS_MAX], to_gr[NGROUPS_MAX];
+ int n_fgr, n_tgr;
+#endif
+
+ /* --- Set the default login group, if there is one --- */
+
+ if (~flags & f_havegroup)
+ group = (style == l_preserve) ? from_pw->pw_gid : to_pw->pw_gid;
+
+#ifndef HAVE_SETGROUPS
+
+ /* --- Check that it's valid --- */
+
+ if (group != from_pw->pw_gid && group != to_pw->pw_gid)
+ die("invalid default group");
+
+#else
+
+ /* --- Set the default group style --- */
+
+ if (gstyle == g_unset)
+ gstyle = (style == l_login) ? g_replace : g_merge;
+
+ /* --- Read in my current set of groups --- */
+
+ n_fgr = getgroups(NGROUPS_MAX, from_gr);
+
+ /* --- Now read the groups for the target user --- *
+ *
+ * Do this even if I'm using the @g_keep@ style -- I'll use it for
+ * checking that @group@ is valid.
+ */
+
+ {
+ struct group *gr;
+ char **p;
+
+ n_tgr = 0;
+ to_gr[n_tgr++] = to_pw->pw_gid;
+
+ setgrent();
+ while ((gr = getgrent()) != 0) {
+ if (gr->gr_gid == to_gr[0])
+ continue;
+ for (p = gr->gr_mem; *p; p++) {
+ if (strcmp(to_pw->pw_name, *p) == 0) {
+ to_gr[n_tgr++] = gr->gr_gid;
+ if (n_tgr >= NGROUPS_MAX)
+ goto done_groups;
+ break;
+ }
+ }
+ }
+
+ done_groups:
+ endgrent();
+ }
+
+ /* --- Check that @group@ is reasonable --- */
+
+ {
+ int i;
+
+ if (group == getgid() || group == from_pw->pw_gid)
+ goto group_ok;
+ for (i = 0; i < n_fgr; i++) {
+ if (group == from_gr[i])
+ goto group_ok;
+ }
+ for (i = 0; i < n_tgr; i++) {
+ if (group == to_gr[i])
+ goto group_ok;
+ }
+ die("invalid default group");
+ group_ok:;
+ }
+
+ /* --- Phew. Now comes the hard bit --- */
+
+ {
+ gid_t ga[4];
+ int i;
+
+ i = 0;
+ ga[i++] = group;
+ if (gstyle & g_keep) {
+ ga[i++] = getgid();
+ ga[i++] = from_pw->pw_gid;
+ }
+ if (gstyle & g_replace)
+ ga[i++] = to_pw->pw_gid;
+
+ /* --- Style authorities will become apoplectic if shown this --- *
+ *
+ * As far as I can see, it's the neatest way of writing it.
+ */
+
+ ngroups = 0;
+ (void)(bc__addGroups(groups, &ngroups, ga, i) ||
+ ((gstyle & g_keep) &&
+ bc__addGroups(groups, &ngroups, from_gr,n_fgr)) ||
+ ((gstyle & g_replace) &&
+ bc__addGroups(groups, &ngroups, to_gr, n_tgr)));
+ }
+
+#endif
+
+ /* --- Trace the results of all this --- */
+
+ T( trace(TRACE_SETUP, "setup: default group == %i", (int)group); )
+
+#ifdef HAVE_SETGROUPS
+ IF_TRACING(TRACE_SETUP, {
+ int i;
+
+ for (i = 1; i < ngroups; i++)
+ trace(TRACE_SETUP, "setup: subsidiary group %i", (int)groups[i]);
+ })
+#endif
+ }
+