Patch: netgrp can't handle splitted NIS groups
Christian Mudra <[email protected]> Fri, 8 Jul 2005 11:54:05 +0200
| Newsgroups | gmane.linux.pld.shadow.general |
|---|---|
| Message-ID | <[email protected]> |
Hi, today I found out, that newgrp doesn't handle splitted NIS groups correctly. I've checked several implementations of newgrp (shadow, util-linux and opensolaris), but didn't have success finding a 'good' one. It's interesting, that only the newgroup of AIX (I tested AIX-5.1) takes care of splitted NIS groups and handles them correctly. Background: If a line in the NIS map 'group' will be larger than about 1018 bytes (some bytes less than 2^10), under some architectures/OS the resulting NIS map will be corrupt. In large environments it's sometimes needed to have a couple of people (let's say 300++) in one NIS group. Because the group entry in the NIS map would become way too large, it must be split into several groups. Given the users user1, user2, user3, user4 user1:*:1001:50000:.... user2:*:1002:50000:.... user3:*:1003:50000:.... user4:*:1004:50000:.... in the groups users:*:50000 largegrp:*:59999:user1,user2 largegrp_1:*:59999:user3,user4 ... The command newgrp largegrp given by user3 fails. The 'groups' command handles that case for the users 'user3' and 'user4' correctly, e.g. it shows, that the user 'user3' is in the groups users largegrp (not in 'largegrp_1'). Reading the code in newgrp.c: The requested group (largegrp) is checked for existence, and then the list of group members of 'largegrp' is searched for "user3". This of course will fail, because in the struct grp->gr_mem only the users "user1" and "user2" are listed. Because of that, a group password is asked for. Attached are two patches, but there are still some TO-DO's. The first patch (newgrp_handle_split_groups) extends the functionality of src/newgrp.c, that, if the requested group is given, all groups of the same GID are tested for membership of the requesting user. This patch requires configure to write a switch USE_SPLITTEDGROUPS to config.h, which should be added. The second patch (use_have_lastlog_h) patches libmisc/log.c, as the struct lastlog is not known on HPUX (more of this topis further below). This patch is not complete in the meaning, that 1) only log.c is changed but not all the other files which also include <lastlog.h>, 2) all files with occurances with a call to dolastlog() should be fixed too, because of the prototype change. I also compiled the command 'newgrp' on several platforms: *) On IRIX(-6.5.24) the following fix is needed: lib/Makefile: DEFS=-DLOGINDEFS=\"/etc/default/login\" *) On Linux (RedHat8 on x86, SuSE9 on x86_64), everything was fine. *) SunOS-5.7 up to 5.9: during 'configure': checking location of faillog/lastlog/wtmp... ./configure[23124]: test: argument expected ./configure[23124]: test: argument expected ./configure[23124]: test: argument expected ./configure[23124]: test: argument expected /etc As on IRIX, lib/Makefile needed a change: lib/Makefile: DEFS=-DLOGINDEFS=\"/etc/default/login\" *) HPUX was the hardest platform. For all tested HPUX platforms (I used HPUX-11.00-PARISC2 and HPUX-11.22-ia64), configure fails like on SunOS: checking location of faillog/lastlog/wtmp... ./configure[23124]: test: Specify a parameter with this command. ./configure[23124]: test: Specify a parameter with this command. ./configure[23124]: test: Specify a parameter with this command. ./configure[23124]: test: Specify a parameter with this command. /etc All HPUX platforms, either the common /etc/login.defs or /etc/default/login is only available as /etc/default/security or simply not existant. So, the shadow package file lib/getdefs.c should _NOT_ stop (exit 1) when the LOGIN_DEFS file could not be read. Also, HPUX does not have a <lastlog.h>. configure sets a /* #undef HAVE_LASTLOG_H */ in all config.h on all tested platforms. Beside the fact, that either the test in configure is not working (as Linux and IRIX offer a <lastlog.h>), no code actually uses that flag. At least on HPUX, it should be used. In that case, src/login.c should be patched, too, to use the dolastlog() call in libmisc/log.c only if HAVE_LASTLOG_H is set. **) HPUX-11.00 on PA-RISC2: configure needs to look for getspnam() in the library -lsec, and newgrp must be linked against libsec **) HPUX-11.11 on PA-RISC2: configure aborts the xgettext test: checking for xgettext... ./configure[24480]: 24051 Abort(coredump) no ... but I didn't dig deeper into that. Regards, Christian Mudra. -- Christian Mudra science + computing ag IT-Services Ingolstaedter Str. 22 BMW-Infrastruktur 80807 Muenchen, Germany phone +49 (0)89 356386-865 [email protected] fax +49 (0)89 356386-737
newgrp_handle_split_groups.patch
(text/plain, 2.2 KB)
diff -uNr src/newgrp.c.orig src/newgrp.c
--- src/newgrp.c.orig 2005-06-20 12:17:08.000000000 +0200
+++ src/newgrp.c 2005-07-08 11:43:06.000000000 +0200
@@ -40,6 +40,8 @@
#include "getdef.h"
extern char **environ;
+#define USE_SPLITTEDGROUPS
+
#ifdef HAVE_SETGROUPS
static int ngroups;
static GETGROUPS_T *grouplist;
@@ -63,6 +65,37 @@
fprintf (stderr, _("Usage: sg group [[-c] command]\n"));
}
+#ifdef USE_SPLITTEDGROUPS
+/*
+ * find_matching_group - search all groups of a given group id for
+ * membership of a given username
+ */
+
+static struct group* find_matching_group(const char *name, gid_t gid) {
+ struct group *gr;
+ char **look;
+ int notfound=1;
+
+ setgrent();
+ while ((gr = getgrent()) != NULL) {
+ if (gr->gr_gid != gid) {
+ continue;
+ }
+ /*
+ * A group with matching GID was found.
+ * Test for membership of 'name'.
+ */
+ look = gr->gr_mem;
+ while (*look && (notfound = strcmp(*look++, name)))
+ ;
+ if (!notfound)
+ break;
+ }
+ endgrent();
+ return gr;
+}
+#endif
+
/*
* newgrp - change the invokers current real and effective group id
*/
@@ -289,6 +322,24 @@
fprintf (stderr, _("unknown group: %s\n"), group);
goto failure;
}
+#ifdef USE_SPLITTEDGROUPS
+ /*
+ * For splitted groups (due to limitations of NIS), check all
+ * groups of the same GID like the requested group for
+ * membership of the current user.
+ */
+ grp = find_matching_group(name, grp->gr_gid);
+ if (!grp) {
+ /*
+ * No matching group found. As we already know that
+ * the group exists, this happens only in the case
+ * of a requested group where the user is not member.
+ *
+ * Re-read the group entry for further processing.
+ */
+ grp = getgrnam(group);
+ }
+#endif
#ifdef SHADOWGRP
if ((sgrp = getsgnam (group))) {
grp->gr_passwd = sgrp->sg_passwd;
use_have_lastlog_h.patch
(text/plain, 730 B)
diff -uNr libmisc/log.c.orig libmisc/log.c
--- libmisc/log.c.orig 2005-06-14 22:27:35.000000000 +0200
+++ libmisc/log.c 2005-07-08 11:50:21.000000000 +0200
@@ -36,7 +36,10 @@
#include <fcntl.h>
#include <time.h>
#include "defines.h"
+#if HAVE_LASTLOG_H
#include <lastlog.h>
+#endif
+
/*
* dolastlog - create lastlog entry
*
@@ -44,6 +47,7 @@
* UID is extracted from the global (struct passwd) entry and the
* TTY information is gotten from the (struct utmp).
*/
+#if HAVE_LASTLOG_H
void
dolastlog (struct lastlog *ll, const struct passwd *pw, const char *line,
const char *host)
@@ -94,3 +98,9 @@
write (fd, (char *) &newlog, sizeof newlog);
close (fd);
}
+
+#else
+
+void dolastlog () { }
+
+#endif