Re: man 8 usermod -e, --expiredate EXPIRE_DATE information incorrect (can't be blank, must be -1 to clear)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello David,

On 12/10/21 23:54, David C. Rankin wrote:
Dear usermod man page maintainers,

   There is an error in the description of the option for:

-e, --expiredate EXPIRE_DATE

   The man page states:

An empty EXPIRE_DATE argument will disable the expiration of the account.

   This is incorrect. The EXPIRE_DATE argument CANNOT be empty or it will take
the LOGIN as the value for the EXPIRE_DATE.

   Instead, the correct use is "-e -1" or "--expiredate -1" where "-1" (-one)
is provided as the EXPIRE_DATE value.

See, e.g.: https://stackoverflow.com/a/30769911/3422102

Thanks for the report.

I tried a few combinations that allow to pass an empty argument to the expiredate option.

From a terminal, I expire the password (and check it) with:

$ sudo usermod -e 1 alx
$ su alx
Password:
Your account has expired; please contact your system administrator.
su: Authentication failure
$


Then from another terminal (logged in as root), I re-enable it, with either of the following:

# usermod -e '' alx
# usermod --expiredate= alx

And then I can log in correctly:

$ su alx
Password:
$


I commented on the stackoverflow post with this info.


Cheers,
Alex


See some more details below:

===========
https://github.com/shadow-maint/shadow/tree/master
is the source code for the passwd package available in Debian.


Parsing the options and arguments in <src/usermod.c>:

			case 'e':
				if ('\0' != *optarg) {
					user_newexpire = strtoday (optarg);
					if (user_newexpire < -1) {
						fprintf (stderr,
						         _("%s: invalid date '%s'\n"),
						         Prog, optarg);
						exit (E_BAD_ARG);
					}
					user_newexpire *= DAY / SCALE;
				} else {
					user_newexpire = -1;
				}
				eflg = true;
				break;


So both '' and '-1' are treated in the same way,
but '-1' is undocumented.
I'm wondering what other undocumented formats are accepted,
since I succeeded with a positive number,
which is also undocumented,
so let's see strtoday():


/*
 * strtoday() now uses get_date() (borrowed from GNU shellutils)
 * which can handle many date formats, for example:
 *	1970-09-17	# ISO 8601.
 *	70-9-17		# This century assumed by default.
 *	70-09-17	# Leading zeros are ignored.
 *	9/17/72		# Common U.S. writing.
 *	24 September 1972
 *	24 Sept 72	# September has a special abbreviation.
 *	24 Sep 72	# Three-letter abbreviations always allowed.
 *	Sep 24, 1972
 *	24-sep-72
 *	24sep72
 */
long strtoday (const char *str)
{
	time_t t;
	bool isnum = true;
	const char *s = str;

	/*
	 * get_date() interprets an empty string as the current date,
	 * which is not what we expect, unless you're a BOFH :-).
	 * (useradd sets sp_expire = current date for new lusers)
	 */
	if ((NULL == str) || ('\0' == *str)) {
		return -1;
	}

	/* If a numerical value is provided, this is already a number of
	 * days since EPOCH.
	 */
	if ('-' == *s) {
		s++;
	}
	while (' ' == *s) {
		s++;
	}
	while (isnum && ('\0' != *s)) {
		if (!isdigit (*s)) {
			isnum = false;
		}
		s++;
	}
	if (isnum) {
		long retdate;
		if (getlong (str, &retdate) == 0) {
			return -2;
		}
		return retdate;
	}

	t = get_date (str, NULL);
	if ((time_t) - 1 == t) {
		return -2;
	}
	/* convert seconds to days since 1970-01-01 */
	return (long) (t + DAY / 2) / DAY;
}


So a simple number is "day since the Epoch".
Other accepted formats are in the comment above the function.
BTW, since this function understands "" as -1,
the parsing in <src/usermod.c> could be simplified
(remove the special case for ""),
so I'll send a patch for that.


static void date_to_str (/*@unique@*//*@out@*/char *buf, size_t maxsize,
                         long int date)
{
	struct tm *tp;

	if (date < 0) {
		strncpy (buf, "never", maxsize);
	} else {
		time_t t = (time_t) date;
		tp = gmtime (&t);
#ifdef HAVE_STRFTIME
		strftime (buf, maxsize, "%Y-%m-%d", tp);
#else
		(void) snprintf (buf, maxsize, "%04d-%02d-%02d",
		                 tp->tm_year + 1900,
		                 tp->tm_mon + 1,
		                 tp->tm_mday);
#endif				/* HAVE_STRFTIME */
	}
	buf[maxsize - 1] = '\0';
}


Then, the number is converted back to string,
and '-1' means 'never', as you said.


--
Alejandro Colomar
Linux man-pages comaintainer; http://www.kernel.org/doc/man-pages/



[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux