I am trying to compile npasswd-2.05 on SCO 5.0.7:

||*GNU Development Tools (ver 5.0.7g) ||
|| SCO OpenServer Enterprise System (ver 5.0.7Hw) ||
|| SCO OpenServer Linker and Application Development Libraries (ver 5.2.0Aa) ||
|| SCO Symmetrical Multiprocessing (ver 1.1.1Hw) ||
|| Samba 3.0.20a File and Print Server (ver 3.0.20Ab) ||
|| Squid Proxy Cache 2.5.STABLE12 (ver 5.0.7Hd) ||
|| SCO OpenServer Release 5.0.7 Maintenance Pack 4 (ver 1.0.0Lb)

and with Bela's suggestions on libraries, have gotten it to compile but
it does not work properly and dumps core when used to change a users password
for the second time.

The reason for investigating npasswd is to obtain the facility to prevent
users from re-using any of their last four passwords.

I ran ./Configure and worked through the steps to configure the make script
with choices as seemed appropriate. Most things I left at default as discovered
by Configure but I specified "NO" to replace system files: With "NO" make install
creates /usr/lib/passwd and installs npasswd and its support utilities therein.
With "YES" make install will replace /bin/passwd with the compiled npasswd
executable and move the OS passwd and support files to /usr/lib/passwd/system
where it will call them as needed.

With the changes I made to get npasswd to compile, the /usr/lib/passwd/npasswd
executable will change a users password (updating /etc/passwd & /etc/shadow) but
not changing the tcb passwd information:

Sun Apr 30 23:46:31 CDT 2006
# npasswd smf


Changing password for smf on unix.smfabac.com
New password (? for help):
New password (again):
Local password changed for smf on unix.smfabac.com
Local password aging changed for smf on unix.smfabac.com
# date
Sun Apr 30 23:47:00 CDT 2006
# echo $TZ
CST6CDT
#
# userls -A -l smf
smf {pw_name smf} {pw_uid 200} {loginGroup group} {pw_gid 50} {pw_di
r /u/smf} {pw_shell /bin/sh} {groups group} {groupsForLogins {}} {auditFlags {0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}} {mode 16877} {noPassword 0} {comment {St
eve Fabac; S.M. Fabac & Associates 816-765-1670}} {passwdSuccessfulChangeTime 11
46441600} {lastSuccessfulLoginTime 1146441600} {administrativeLockApplied 0} {pa

# l -lt /etc/passwd
-rw-rw-r-- 1 bin auth 1006 Apr 30 23:52 /etc/passwd@

# cat history.pag
n SrBINT9XC30Mw,1146458817smf

Converting 1146458817 UNIX time results in: Mon, 1 May 2006 04:46:57 UTC


The above userls shows that the passwdSuccessfulChangeTime is 1146441600 and is the
same as the lastSuccessfulLoginTime (?). Converting from UNIX time to date
calculator I get: Mon, 1 May 2006 00:00:00 UTC with scoadmin -> account manager
showing:

|
| +------------------ unix: User Password Expiration: smf -------------------+ |
| | |||
| | Last Successful Change: Sun Apr 30 19:00:00 CDT 2006 |||

So npasswd does not update SCO's internal information for password aging.

That may make it unusable for the client as they are on a 90-day cycle to
require users to set new passwords.

But more troubling than that is the fact that npasswd will dump core the
next time it is run for a user: The first time it is run, there is no entry
for the user in the npasswd history file (/usr/lib/passwd/history.pag). The
second time it is run for the user, it dumps core:

# npasswd smf


Changing password for smf on unix.smfabac.com
New password (? for help):
emory fault(coredump) <- after entering a new password
#

But:

# npasswd smf


Changing password for smf on unix.smfabac.com
New password (? for help):
That is your current password. <- after entering the current password.

I then enabled debugging as specified in the Npasswd doc's for troubleshooting:

> Tracking down problems such as segmentation faults requires a debugger binary:
> make realclean # Purge existing objects
> make debug-dbx # Set make environment for debug
> make # Rebuild


and running gdb npasswd I get:

# gdb npasswd
GNU gdb 5.2.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i586-pc-sco3.2v5.0"...
(gdb) run smf
Starting program: /usr/lib/passwd/npasswd smf


Changing password for smf on unix.smfabac.com
New password (? for help):

Program received signal SIGSEGV, Segmentation fault.
0x8003257c in t_splay () from /usr/lib/libc.so.1
(gdb) bt
#0 0x8003257c in t_splay () from /usr/lib/libc.so.1
#1 0x8003244f in t_delete () from /usr/lib/libc.so.1
#2 0x8003215f in realfree () from /usr/lib/libc.so.1
#3 0x80032816 in cleanfree () from /usr/lib/libc.so.1
#4 0x80031c66 in _real_malloc () from /usr/lib/libc.so.1
#5 0x80031b21 in malloc () from /usr/lib/libc.so.1
#6 0x0805215d in PWOpen (
prefix=0x8067694 "/usr/lib/passwd/dictionaries/Antworth",
mode=0x805c36a "r") at packlib.c:85
#7 0x08051f4e in FascistNpasswd (pwl=0x805ec08,
instring=0x8060560 "bobisbad", verbose=0) at fascist.c:942
#8 0x0804ef01 in pwck_crack (password=0x8060560 "bobisbad", user=0x806723c)
at pwck_crack.c:71
#9 0x0804dfab in checkpassword (password=0x8047d44 "bobisbad", user=0x806723c)
at pwck_main.c:267
#10 0x0804b495 in passwd (theUser=0x806723c, theCaller=0x8066d60)
at passwd.c:285
#11 0x0804a210 in main (argc=2, argv=0x8047de0, envp=0x8047dec) at main.c:186
#12 0x08049d92 in _start ()
(gdb)

I then restarted npasswd:
(gdb) run smf
Starting program: /usr/lib/passwd/npasswd smf


Changing password for smf on unix.smfabac.com
New password (? for help): <- Press Del key at this point. ->
Program received signal SIGINT, Interrupt.
0x800412e8 in _r_read () from /usr/lib/libc.so.1
(gdb) break PWOpen
Breakpoint 1 at 0x8052119: file packlib.c, line 77.
(gdb) cont
Continuing.


Breakpoint 1, PWOpen (
prefix=0x8067694 "/usr/lib/passwd/dictionaries/Antworth",
mode=0x805c36a "r") at packlib.c:77
77 if (strlen(prefix) > (STRINGSIZE - 5)) {
(gdb) step
85 if ((pdesc = (PWDICT *)malloc(sizeof(PWDICT))) == 0) {
(gdb) print sizeof(PWDICT)
$1 = 1568
(gdb)

This is where my total lack of C programming knowledge fails me:
I can't guess what the code it trying to do. I did a google search
on t_splay and found references to malloc:

> On Fri, 9 Aug 2002 16:38:29 -0700, Paul wrote:
> > anybody seen encounter a core dump likst this or know what this means:

>
> > Program terminated with signal 11, Segmentation fault.
> > #0 0x1e9aa in t_splay ()
> > (gdb) bt
> > #0 0x1e9aa in t_splay ()
> > #1 0x1e891 in t_delete ()
> > #2 0x1e5cd in realfree ()

>
>
>
> It mean you overwrote the bounds of an object obtained by malloc, wrote
> to it after it was free, or some other form of naughtiness.



So I looked for PWOpen() and found it in:
npasswd-2.06/src/PasswordCheck/cracklib/packlib.c:

/*
* PWOpen - open a hashed dictionary
*/
PWDICT *
PWOpen(prefix, mode)
char *prefix;
char *mode; /* fopen() modes */
{
c_int32 i;
PWDICT *pdesc;
char iname[STRINGSIZE];
char dname[STRINGSIZE];
char wname[STRINGSIZE];

if (strlen(prefix) > (STRINGSIZE - 5)) {
(void) strcpy (PWioError, "PWOpen: Path too long");
#ifdef CRACKLIB_PERROR
(void) fprintf (stderr, "%s\n", PWioError);
#endif
return ((PWDICT *) 0);
}
> /* Offending code!! */
> if ((pdesc = (PWDICT *)malloc(sizeof(PWDICT))) == 0) {

(void) strcpy(PWioError, "PWOpen: Cannot allocate pwdict block");
#ifdef CRACKLIB_PERROR
(void) fprintf(stderr, "%s\n", PWioError);
#endif
return ((PWDICT *) 0);
}

(void) memset(pdesc, '\0', sizeof(*pdesc));

(void) sprintf(iname, "%s.pwi", prefix);
(void) sprintf(dname, "%s.pwd", prefix);
(void) sprintf(wname, "%s.hwm", prefix);

if (!(pdesc->dfp = fopen(dname, mode)))
{
#ifdef CRACKLIB_PERROR
perror(dname);
#endif
(void) sprintf(PWioError, "PWOpen: Error %d opening data file", errno);
free((char *)pdesc);
return ((PWDICT *) 0);
}

if (!(pdesc->ifp = fopen(iname, mode)))
{
#ifdef CRACKLIB_PERROR
perror(iname);
#endif
(void) sprintf(PWioError, "PWOpen: Error %d opening index file", errno);
(void) fclose(pdesc->dfp);
free((char *)pdesc);
return ((PWDICT *) 0);
}

if (pdesc->wfp = fopen(wname, mode))
{
pdesc->flags |= PFOR_USEHWMS;
}

if (mode[0] == 'w')
{
pdesc->flags |= PFOR_WRITE;
pdesc->header.pih_magic = PIH_MAGIC;
pdesc->header.pih_blocklen = NUMWORDS;
pdesc->header.pih_numwords = 0;

(void) fwrite((char *) &pdesc->header, sizeof(pdesc->header), 1, pdesc->
ifp);
} else
{
pdesc->flags &= ~PFOR_WRITE;

if (!fread((char *) &pdesc->header, sizeof(pdesc->header), 1, pdesc->ifp
))
{
(void) strcpy(PWioError, "PWOpen: error reading header");
#ifdef CRACKLIB_PERROR
fprintf(stderr, "%s: %s\n", prefix, PWioError);
#endif
(void) fclose(pdesc->ifp);
(void) fclose(pdesc->dfp);
if (pdesc->flags & PFOR_USEHWMS)
(void) fclose(pdesc->wfp);
free((char *)pdesc);
return ((PWDICT *) 0);
}

if (pdesc->header.pih_magic != PIH_MAGIC)
{
(void) strcpy(PWioError, "PWOpen: magic mismatch");
#ifdef CRACKLIB_PERROR
(void) fprintf(stderr, "%s: %s\n", prefix, PWioError);
#endif
(void) fclose(pdesc->ifp);
(void) fclose(pdesc->dfp);
if (pdesc->flags & PFOR_USEHWMS)
(void) fclose(pdesc->wfp);
free((char *)pdesc);
return ((PWDICT *) 0);
}

if (pdesc->header.pih_blocklen != NUMWORDS)
{
(void) strcat(PWioError, "PWOpen: size mismatch");
#ifdef CRACKLIB_PERROR
(void) fprintf(stderr, "%s: %s\n", prefix, PWioError);
#endif
(void) fclose(pdesc->ifp);
(void) fclose(pdesc->dfp);
if (pdesc->flags & PFOR_USEHWMS)
(void) fclose(pdesc->wfp);
free((char *)pdesc);
return ((PWDICT *) 0);
}

if (pdesc->flags & PFOR_USEHWMS)
{
if (fread(pdesc->hwms, 1, sizeof(pdesc->hwms), pdesc->wfp) != sizeof
(pdesc->hwms))
{
pdesc->flags &= ~PFOR_USEHWMS;
}
}
}
return (pdesc);
}


/*
* PWClose - close hashed dictionary
*/
int
PWClose(pwp)

Not being a programmer, I tried commenting out the offending code but
that only resulted in npasswd dumping core upon start up. Therefore
the code must be essentially correct but is some how failing when
it finds an existing user in the history.pag.

Suggestions anyone?

--

Steve Fabac
S.M. Fabac & Associates
816/765-1670