337 lines
12 KiB
HTML
337 lines
12 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
|
<HTML>
|
|
<HEAD>
|
|
<META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
|
|
<TITLE>Linux Shadow Password HOWTO: Adding shadow support to a C program</TITLE>
|
|
<LINK HREF="Shadow-Password-HOWTO-9.html" REL=next>
|
|
<LINK HREF="Shadow-Password-HOWTO-7.html" REL=previous>
|
|
<LINK HREF="Shadow-Password-HOWTO.html#toc8" REL=contents>
|
|
</HEAD>
|
|
<BODY>
|
|
<A HREF="Shadow-Password-HOWTO-9.html">Next</A>
|
|
<A HREF="Shadow-Password-HOWTO-7.html">Previous</A>
|
|
<A HREF="Shadow-Password-HOWTO.html#toc8">Contents</A>
|
|
<HR>
|
|
<H2><A NAME="sec-adding"></A> <A NAME="s8">8. Adding shadow support to a C program</A></H2>
|
|
|
|
<P>Adding shadow support to a program is actually fairly straightforward. The
|
|
only problem is that the program must be run by root (or SUID root) in order
|
|
for the the program to be able to access the <CODE>/etc/shadow</CODE> file.
|
|
<P>This presents one big problem: very careful programming practices must be
|
|
followed when creating SUID programs. For instance, if a program has a shell
|
|
escape, this must not occur as root if the program is SUID root.
|
|
<P>For adding shadow support to a program so that it can check passwords, but
|
|
otherwise does need to run as root, it's a lot safer to run the program SUID
|
|
shadow instead. The <CODE>xlock</CODE> program is an example of this.
|
|
<P>In the example given below, <CODE>pppd-1.2.1d</CODE> already runs SUID as root,
|
|
so adding shadow support should not make the program any more vulnerable.
|
|
<P>
|
|
<H2><A NAME="ss8.1">8.1 Header files</A>
|
|
</H2>
|
|
|
|
<P>The header files should reside in <CODE>/usr/include/shadow</CODE>. There
|
|
should also be a <CODE>/usr/include/shadow.h</CODE>, but it will be a symbolic
|
|
link to <CODE>/usr/include/shadow/shadow.h</CODE>.
|
|
<P>To add shadow support to a program, you need to include the header files:
|
|
<PRE>
|
|
#include <shadow/shadow.h>
|
|
#include <shadow/pwauth.h>
|
|
</PRE>
|
|
<P>It might be a good idea to use compiler directives to conditionally compile
|
|
the shadow code (I do in the example below).
|
|
<P>
|
|
<H2><A NAME="ss8.2">8.2 libshadow.a library</A>
|
|
</H2>
|
|
|
|
<P>When you installed the <EM>Shadow Suite</EM> the <CODE>libshadow.a</CODE> file
|
|
was created and installed in <CODE>/usr/lib</CODE>.
|
|
<P>When compiling shadow support into a program, the linker needs to be told to
|
|
include the <CODE>libshadow.a</CODE> library into the link.
|
|
<P>This is done by:
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
gcc program.c -o program -lshadow
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>However, as we will see in the example below, most large programs use a
|
|
<CODE>Makefile</CODE>, and usually have a variable called <CODE>LIBS=...</CODE> that
|
|
we will modify.
|
|
<P>
|
|
<H2><A NAME="ss8.3">8.3 Shadow Structure</A>
|
|
</H2>
|
|
|
|
<P>The <CODE>libshadow.a</CODE> library uses a structure called <CODE>spwd</CODE>
|
|
for the information it retrieves from the <CODE>/etc/shadow</CODE> file. This is
|
|
the definition of the <CODE>spwd</CODE> structure from the
|
|
<CODE>/usr/include/shadow/shadow.h</CODE> header file:
|
|
<HR>
|
|
<PRE>
|
|
struct spwd
|
|
{
|
|
char *sp_namp; /* login name */
|
|
char *sp_pwdp; /* encrypted password */
|
|
sptime sp_lstchg; /* date of last change */
|
|
sptime sp_min; /* minimum number of days between changes */
|
|
sptime sp_max; /* maximum number of days between changes */
|
|
sptime sp_warn; /* number of days of warning before password
|
|
expires */
|
|
sptime sp_inact; /* number of days after password expires
|
|
until the account becomes unusable. */
|
|
sptime sp_expire; /* days since 1/1/70 until account expires
|
|
*/
|
|
unsigned long sp_flag; /* reserved for future use */
|
|
};
|
|
</PRE>
|
|
<HR>
|
|
<P>The <EM>Shadow Suite</EM> can put things into the <CODE>sp_pwdp</CODE> field
|
|
besides just the encoded passwd. The password field could contain:
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
username:Npge08pfz4wuk;@/sbin/extra:9479:0:10000::::
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>This means that in addition to the password, the program
|
|
<CODE>/sbin/extra</CODE> should be called for further authentication. The
|
|
program called will get passed the username and a switch that indicates
|
|
why it's being called. See the file <CODE>/usr/include/shadow/pwauth.h</CODE>
|
|
and the source code for <CODE>pwauth.c</CODE> for more information.
|
|
<P>What this means is that we should use the function <CODE>pwauth</CODE> to
|
|
perform the actual authentication, as it will take care of the secondary
|
|
authentication as well. The example below does this.
|
|
<P>The author of the <EM>Shadow Suite</EM> indicates that since most
|
|
programs in existence don't do this, and that it may be removed or changed
|
|
in future versions of the <EM>Shadow Suite</EM>.
|
|
<P>
|
|
<H2><A NAME="ss8.4">8.4 Shadow Functions</A>
|
|
</H2>
|
|
|
|
<P>The <CODE>shadow.h</CODE> file also contains the function prototypes for the
|
|
functions contained in the <CODE>libshadow.a</CODE> library:
|
|
<HR>
|
|
<PRE>
|
|
extern void setspent __P ((void));
|
|
extern void endspent __P ((void));
|
|
extern struct spwd *sgetspent __P ((__const char *__string));
|
|
extern struct spwd *fgetspent __P ((FILE *__fp));
|
|
extern struct spwd *getspent __P ((void));
|
|
extern struct spwd *getspnam __P ((__const char *__name));
|
|
extern int putspent __P ((__const struct spwd *__sp, FILE *__fp));
|
|
</PRE>
|
|
<HR>
|
|
<P>The function that we are going to use in the example is: <CODE>getspnam</CODE>
|
|
which will retrieve for us a <CODE>spwd</CODE> structure for the supplied name.
|
|
<P>
|
|
<P>
|
|
<H2><A NAME="ss8.5">8.5 Example</A>
|
|
</H2>
|
|
|
|
<P>This is an example of adding shadow support to a program that needs it, but
|
|
does not have it by default.
|
|
<P>This example uses the <EM>Point-to-Point Protocol Server</EM> (pppd-1.2.1d),
|
|
which has a mode in which it performs <EM>PAP</EM> authentication using
|
|
user names and passwords from the <CODE>/etc/passwd</CODE> file instead of the
|
|
<EM>PAP</EM> or <EM>CHAP</EM> files. You would not need to add this code
|
|
to <CODE>pppd-2.2.0</CODE> because it's already there.
|
|
<P>This feature of pppd probably isn't used very much, but if you installed the
|
|
<EM>Shadow Suite</EM>, it won't work anymore because the passwords are no
|
|
longer stored in <CODE>/etc/passwd</CODE>.
|
|
<P>The code for authenticating users under <CODE>pppd-1.2.1d</CODE> is located in
|
|
the <CODE>/usr/src/pppd-1.2.1d/pppd/auth.c</CODE> file.
|
|
<P>The following code needs to be added to the top of the file where all the
|
|
other <CODE>#include</CODE> directives are. We have surrounded the
|
|
<CODE>#includes</CODE> with conditional directives (i.e. only include if we
|
|
are compiling for shadow support).
|
|
<P>
|
|
<HR>
|
|
<PRE>
|
|
#ifdef HAS_SHADOW
|
|
#include <shadow.h>
|
|
#include <shadow/pwauth.h>
|
|
#endif
|
|
</PRE>
|
|
<HR>
|
|
|
|
<P>The next thing to do is to modify the actual code. We are still making
|
|
changes to the <CODE>auth.c</CODE> file.
|
|
<P>Function <CODE>auth.c</CODE> before modifications:
|
|
<HR>
|
|
<PRE>
|
|
/*
|
|
* login - Check the user name and password against the system
|
|
* password database, and login the user if OK.
|
|
*
|
|
* returns:
|
|
* UPAP_AUTHNAK: Login failed.
|
|
* UPAP_AUTHACK: Login succeeded.
|
|
* In either case, msg points to an appropriate message.
|
|
*/
|
|
static int
|
|
login(user, passwd, msg, msglen)
|
|
char *user;
|
|
char *passwd;
|
|
char **msg;
|
|
int *msglen;
|
|
{
|
|
struct passwd *pw;
|
|
char *epasswd;
|
|
char *tty;
|
|
|
|
if ((pw = getpwnam(user)) == NULL) {
|
|
return (UPAP_AUTHNAK);
|
|
}
|
|
/*
|
|
* XXX If no passwd, let them login without one.
|
|
*/
|
|
if (pw->pw_passwd == '\0') {
|
|
return (UPAP_AUTHACK);
|
|
}
|
|
|
|
epasswd = crypt(passwd, pw->pw_passwd);
|
|
if (strcmp(epasswd, pw->pw_passwd)) {
|
|
return (UPAP_AUTHNAK);
|
|
}
|
|
|
|
syslog(LOG_INFO, "user %s logged in", user);
|
|
|
|
/*
|
|
* Write a wtmp entry for this user.
|
|
*/
|
|
tty = strrchr(devname, '/');
|
|
if (tty == NULL)
|
|
tty = devname;
|
|
else
|
|
tty++;
|
|
logwtmp(tty, user, ""); /* Add wtmp login entry */
|
|
logged_in = TRUE;
|
|
|
|
return (UPAP_AUTHACK);
|
|
}
|
|
</PRE>
|
|
<HR>
|
|
<P>The user's password is placed into <CODE>pw->pw_passwd</CODE>, so all we really
|
|
need to do is add the function <CODE>getspnam</CODE>. This will put the
|
|
password into <CODE>spwd->sp_pwdp</CODE>.
|
|
<P>We will add the function <CODE>pwauth</CODE> to perform the actual authentication.
|
|
This will automatically perform secondary authentication if the shadow file
|
|
is setup for it.
|
|
<P>Function <CODE>auth.c</CODE> after modifications to support shadow:
|
|
<P>
|
|
<HR>
|
|
<PRE>
|
|
/*
|
|
* login - Check the user name and password against the system
|
|
* password database, and login the user if OK.
|
|
*
|
|
* This function has been modified to support the Linux Shadow Password
|
|
* Suite if USE_SHADOW is defined.
|
|
*
|
|
* returns:
|
|
* UPAP_AUTHNAK: Login failed.
|
|
* UPAP_AUTHACK: Login succeeded.
|
|
* In either case, msg points to an appropriate message.
|
|
*/
|
|
static int
|
|
login(user, passwd, msg, msglen)
|
|
char *user;
|
|
char *passwd;
|
|
char **msg;
|
|
int *msglen;
|
|
{
|
|
struct passwd *pw;
|
|
char *epasswd;
|
|
char *tty;
|
|
|
|
#ifdef USE_SHADOW
|
|
struct spwd *spwd;
|
|
struct spwd *getspnam();
|
|
#endif
|
|
|
|
if ((pw = getpwnam(user)) == NULL) {
|
|
return (UPAP_AUTHNAK);
|
|
}
|
|
|
|
#ifdef USE_SHADOW
|
|
spwd = getspnam(user);
|
|
if (spwd)
|
|
pw->pw_passwd = spwd->sp-pwdp;
|
|
#endif
|
|
|
|
/*
|
|
* XXX If no passwd, let NOT them login without one.
|
|
*/
|
|
if (pw->pw_passwd == '\0') {
|
|
return (UPAP_AUTHNAK);
|
|
}
|
|
#ifdef HAS_SHADOW
|
|
if ((pw->pw_passwd && pw->pw_passwd[0] == '@'
|
|
&& pw_auth (pw->pw_passwd+1, pw->pw_name, PW_LOGIN, NULL))
|
|
|| !valid (passwd, pw)) {
|
|
return (UPAP_AUTHNAK);
|
|
}
|
|
#else
|
|
epasswd = crypt(passwd, pw->pw_passwd);
|
|
if (strcmp(epasswd, pw->pw_passwd)) {
|
|
return (UPAP_AUTHNAK);
|
|
}
|
|
#endif
|
|
|
|
syslog(LOG_INFO, "user %s logged in", user);
|
|
|
|
/*
|
|
* Write a wtmp entry for this user.
|
|
*/
|
|
tty = strrchr(devname, '/');
|
|
if (tty == NULL)
|
|
tty = devname;
|
|
else
|
|
tty++;
|
|
logwtmp(tty, user, ""); /* Add wtmp login entry */
|
|
logged_in = TRUE;
|
|
|
|
return (UPAP_AUTHACK);
|
|
}
|
|
</PRE>
|
|
<HR>
|
|
<P>Careful examination will reveal that we made another change as well. The
|
|
original version allowed access (returned <CODE>UPAP_AUTHACK</CODE> if there
|
|
was NO password in the <CODE>/etc/passwd</CODE> file. This is <EM>not</EM>
|
|
good, because a common use of this login feature is to use one account
|
|
to allow access to the PPP process and then check the username and password
|
|
supplied by PAP with the username in the <CODE>/etc/passwd</CODE> file and
|
|
the password in the <CODE>/etc/shadow</CODE> file.
|
|
<P>So if we had set the original version up to run as the shell for a user i.e.
|
|
<CODE>ppp</CODE>, then anyone could get a ppp connection by setting their PAP to user
|
|
<CODE>ppp</CODE> and a password of null.
|
|
<P>We fixed this also by returning <CODE>UPAP_AUTHNAK</CODE> instead of
|
|
<CODE>UPAP_AUTHACK</CODE> if the password field was empty.
|
|
<P>Interestingly enough, <CODE>pppd-2.2.0</CODE> has the same problem.
|
|
<P>Next we need to modify the Makefile so that two things occur:
|
|
<CODE>USE_SHADOW</CODE> must be defined, and <CODE>libshadow.a</CODE> needs to be
|
|
added to the linking process.
|
|
<P>Edit the Makefile, and add:
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
LIBS = -lshadow
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>Then we find the line:
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
COMPILE_FLAGS = -I.. -D_linux_=1 -DGIDSET_TYPE=gid_t
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>And change it to:
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
COMPILE_FLAGS = -I.. -D_linux_=1 -DGIDSET_TYPE=gid_t -DUSE_SHADOW
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>Now make and install.
|
|
<P>
|
|
<HR>
|
|
<A HREF="Shadow-Password-HOWTO-9.html">Next</A>
|
|
<A HREF="Shadow-Password-HOWTO-7.html">Previous</A>
|
|
<A HREF="Shadow-Password-HOWTO.html#toc8">Contents</A>
|
|
</BODY>
|
|
</HTML>
|