Subject: Re: Security problem with pkgsrc/mail/majordomo
To: None <>
From: John Darrow <>
List: tech-pkg
Date: 03/09/2000 17:42:10
In article <>,
Brook Milligan <> wrote:
>   > At 02:55 PM 3/9/00 -0700, Brook Milligan wrote:
>   > >Second, validshell() in addnerd.c uses getusershell() (which reads
>   > >/etc/shells) to check the argument of -s against.  /sbin/nologin is
>   > >not in /etc/shells, so this also fails.  Two possible fixes:  1) add
>   > >an explicit check for /sbin/nologin; 2) add /sbin/nologin to
>   > >/etc/shells.  Should either of these be added to addnerd?
>   > 
>   > Adding /sbin/nologin to /etc/shells would make sense in that many of us 
>   > want to add no-login accounts to our systems. Given that the current 
>   > password file comes with /sbin/nologin for many of the accounts, I don't 
>   > understand why it's not already in /etc/shells.
>   someone correct me if i am wrong here, but isnt a shell no in /etc/shells
>   one of the checks ftpd does to see if ftp'ing to that users is aloud?
>From man ftpd:
>           3.   The user must have a standard shell returned by
>                getusershell(3).  If the user's shell field in the password
>                database is empty, the shell is assumed to be /bin/sh.
>A good reason for it not being in /etc/shells.  That was why I asked.
>It is not obvious that we want /sbin/nologin in /etc/shells.
>But it seems we need a method for addnerd to create an account that
>cannot be used for logins.  Do we want a special case in addnerd to
>allow one to create an account (like majordomo) with /sbin/nologin as
>a shell?
>Or should we only allow "real" shells with addnerd and disable the
>account through the password (which still requires either a long set
>of *s or a modification to addnerd to accomplish).
>More guidance from developers would be appreciated.

I ended up adding a '-f' flag to addnerd, to allow 'forcing' it to use the
supplied username or password fields, even if it considers them 'invalid'.

On one system I'm using this on, we can disable a user's access to their
account (without any of the other issues that come with the 'expire' flag)
by prepending a '*' to their valid encrypted password, and reenable it by
removing the '*' (both by using a simple perl script).  This allows simple
disables/reenables without us having to know the user's password.  Adding
the '-f' flag to addnerd allows us to create accounts in the disabled state.

I can also think of uses where it might be desirable to create accounts
with non-standard shells, both /sbin/nologin and others.

Patches are included below.  I can send-pr them, if someone would like.

As a side note, the 1.4.2/current 'user' command removes the 'invalid shell'
check, but still does the same thing as addnerd with the password.


John Darrow - Senior Technical Specialist               Office: 630/752-5201
Computing Services, Wheaton College, Wheaton, IL 60187  Fax:    630/752-5968
Alphapage:            Pager:  630/316-0707

$ cat pkgsrc/sysutils/addnerd/patches/patch-local-aa
--- addnerd.c.orig	Tue Oct 13 10:28:20 1998
+++ addnerd.c	Tue Nov 16 13:35:08 1999
@@ -76,6 +76,7 @@
 static char	password[PasswordLength + 1];	/* encrypted password for new user */
 static int	verbose;
+static int	force;
 /* split a string `s' at char `sep', into (fieldnum, fieldbuf, fieldsize) tuples */
 static int 
@@ -161,6 +162,8 @@
 	char	*cp;
 	int	ret;
+	if (force)
+		return 1;
 	for (ret = 0 ; (cp = getusershell()) != (char *) NULL ; ) {
 		if (strcmp(sh, cp) == 0) {
 			ret = 1;
@@ -178,6 +181,8 @@
 static int
 validpassword(char *p)
+	if (force)
+		return 1;
 	if (strlen(p) != PasswordLength) {
 		(void) fprintf(stderr, "addnerd: [Warning] password `%s' has invalid length\n", p);
 		return 0;
@@ -307,7 +312,7 @@
 	int	cc;
 	int	i;
-	singleuser = waitsecs = verbose = 0;
+	force = singleuser = waitsecs = verbose = 0;
 	uid = -1;
 	gid = DEFAULT_GID;
@@ -317,8 +322,11 @@
 	password[PasswordLength] = 0;
 	getdefaults(DOTFILES_DIR, "defaults");
-	while ((i = getopt(argc, argv, "g:h:p:s:u:vw:")) != -1) {
+	while ((i = getopt(argc, argv, "fg:h:p:s:u:vw:")) != -1) {
 		switch(i) {
+		case 'f':
+			force = 1;
+			break;
 		case 'g':
 			if (!validgroup(optarg)) {
 				(void) fprintf(stderr, "%s: [Warning] group `%s' is not known\n", *argv, optarg);
@@ -360,7 +368,7 @@
 	if (optind == argc) {
 		(void) fprintf(stderr,
-"Usage: %s [-g groupname|gid] [-h parent-home-dir] [-p encrypted-passwd] [-s shell] [-u uid] [-v] [-w waitsecs] username...\n",
+"Usage: %s [-f] [-g groupname|gid] [-h parent-home-dir] [-p encrypted-passwd] [-s shell] [-u uid] [-v] [-w waitsecs] username...\n",

$ cat pkgsrc/sysutils/addnerd/patches/patch-local-ab
---	Thu Jun 25 06:30:41 1998
+++	Tue Nov 16 13:38:58 1999
@@ -38,7 +38,7 @@
 .Nd add user(s) to the system
-.Op Fl ghpsuvw
+.Op Fl fghpsuvw
 .Op user...
@@ -54,6 +54,9 @@
 After setting any values from that file, the command line options
 are processed:
 .Bl -tag -width Ds
+.It Fl f
+forces use of the login shell and/or password given on the command line, even
+if they are "invalid."
 .It Fl g
 gives the group name or identifier to be used for the new user's primary group.
 .It Fl h