Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://Shadow-Password-HOWTO-html.tar.gz:25518/Shadow-Password-HOWTO-8.html  downloads

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312">
 <META NAME="GENERATOR" CONTENT="ZH-SGML-Tools 1.0.9">
 <TITLE>如何取得,安装,设定 shadow 密码: 加入 shadow 支援 C 语言</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. 加入 shadow 支援 C 语言</A></H2>

<P>新增支援 shadow 程式事实上是很直接的。 唯一的问题是程式需要以 root (或 SUID root)
权限执行,这样才可以存取 <CODE>/etc/shadow</CODE> 档。
<P>这显示一个大问题: 当建立 SUID 程式时需要很小心依照程式运作。举例说明: 如果以个
程式有 shell escape,如果程式本身是 SUID root 将不需要以 root 方式呈现。
<P>对程式新增支援 shadow 而言,它可以检查密码,但不需以 root 权限执行,而是以 SUID 
shadow 取代执行比较安全。 <CODE>xlock</CODE> 程式就是一个例子。
<P>接下来□例介绍, <CODE>pppd-1.2.1d</CODE> 已经以 SUID as root 方式执行,所以新增 shadow
支援应该不会使程式产生任何影响。 
<P>
<P>
<H2><A NAME="ss8.1">8.1 标头档(Header files)</A>
</H2>

<P>标头档应存在 <CODE>/usr/include/shadow</CODE>。 应该有一个 <CODE>/usr/include/shadow.h</CODE>档,
但是它将 symbolic link 到 <CODE>/usr/include/shadow/shadow.h</CODE>。
<P>为了新增支援 shadow 程式,你需要 include 标头档:
<P>
<PRE>
#include &lt;shadow/shadow.h>
#include &lt;shadow/pwauth.h>
</PRE>
<P>
<P>
<H2><A NAME="ss8.2">8.2 libshadow.a 函式库(library)</A>
</H2>

<P>当你安装 <EM>Shadow Suite</EM>, <CODE>libshadow.a</CODE> 档被建立和安装在
<CODE>/usr/lib</CODE> 目录。
<P>当编译一个 shadow support 程式,linker 需要包括 <CODE>libshadow.a</CODE> 函式库进入链结。
<P>
<P>执行如下:
<BLOCKQUOTE><CODE>
<PRE>
gcc program.c -o program -lshadow
</PRE>
</CODE></BLOCKQUOTE>
<P>然而,就像我们接下来要看的例子,大部分大程式使用 <CODE>Makefile</CODE> 且
通常有变数呼叫 <CODE>LIBS=...</CODE> 需要被修改。
<P>
<H2><A NAME="ss8.3">8.3 Shadow 结构(Structure)</A>
</H2>

<P><CODE>libshadow.a</CODE> 函式库对它从 <CODE>/etc/shadow</CODE> 档接收资讯使用结构化呼叫。
这是从 <CODE>/usr/include/shadow/shadow.h</CODE> 标头档的 <CODE>spwd</CODE> 结构定义:
<P>
<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><EM>Shadow Suite</EM> 可以放除了编码密码之外的资料到 <CODE>sp_pwdp</CODE> 栏位。
密码栏位可包括:
<BLOCKQUOTE><CODE>
<PRE>
username:Npge08pfz4wuk;@/sbin/extra:9479:0:10000::::
</PRE>
</CODE></BLOCKQUOTE>
<P>这表示一个额外的密码, <CODE>/sbin/extra</CODE> 程式应该被更多的权限呼叫。 
程式的呼叫需取得使用者名称和指出为何需被呼叫的 switch才可通过。 查看
<CODE>/usr/include/shadow/pwauth.h</CODE> 和原始码 <CODE>pwauth.c</CODE> 获得更多资讯。
<P>为何我们应使用 <CODE>pwauth</CODE> 去表示真正的权限,这是什麽意思,它将使第二组权限也
跑得很好。
<P><EM>Shadow Suite</EM> 作者指出因为大部分存在的程式都不这麽作罗,所以
<EM>Shadow Suite</EM>未来的版本将移除。
<P>
<H2><A NAME="ss8.4">8.4 Shadow 函式(Functions)</A>
</H2>

<P><CODE>shadow.h</CODE> 包含 <CODE>libshadow.a</CODE> 函式库:
<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>我们将使用的□例程式是: <CODE>getspnam</CODE> 将对供应名称恢复对我们 <CODE>spwd</CODE> 结构。
<P>
<H2><A NAME="ss8.5">8.5 □例</A>
</H2>

<P>这是一个□例描述新增 shadow 支援程式,但预设值并没有。
<P>
<P>本□例使用 <EM>Point-to-Point Protocol Server</EM> (pppd-1.2.1d),它有个模式是表示 
从 <CODE>/etc/passwd</CODE> 档取代 <EM>PAP</EM> 或 <EM>CHAP</EM> 档使用帐号密码的 <EM>PAP</EM> 
权限,你将不需要在 <CODE>pppd-2.2.0</CODE> 加这些程式码,因为它已经存在罗。
<P>
<P>
<P>pppd 的未来大致上不会被使用很多,但是如果你安装 <EM>Shadow Suite</EM>,储存在
<CODE>/etc/passwd</CODE> 档的密码将无法运作。
<P>在 <CODE>pppd-1.2.1d</CODE> 权限使用的程式码是位在 <CODE>/usr/src/pppd-1.2.1d/pppd/auth.c</CODE> 档。
<P>接下来程式码需要被加在所有其他 <CODE>#include</CODE> 指令档案的最上头,我们将注意有环境指令的
<CODE>#includes</CODE>。
<P>
<HR>
<PRE>
#ifdef HAS_SHADOW
#include &lt;shadow.h>
#include &lt;shadow/pwauth.h>
#endif
</PRE>
<HR>
 
<P>接下来要做的事情是变更实际码, 我们将变更 <CODE>auth.c</CODE> 档。
<P>变更前 <CODE>auth.c</CODE> 档 function 为:
<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>使用者的密码被放在 <CODE>pw->pw_passwd</CODE>,所以我们需新增 <CODE>getspnam</CODE>
function,这将会把密码放到 <CODE>spwd->sp_pwdp</CODE>。
<P>我们将新增 <CODE>pwauth</CODE> function 来表示真正的权限。 这将在 shadow 档设定时
自动产生第二个权限。
<P>变更为可以支援 shadow 後的 <CODE>auth.c</CODE> function:
<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 &amp;&amp; pw->pw_passwd[0] == '@'
         &amp;&amp; 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>严谨的□例将启发我们在作其他改变的帮助。 原始的版本如果在 <CODE>/etc/passwd</CODE> 档
没有任何密码,可允许存取传回的 <CODE>UPAP_AUTHACK</CODE> 。这是<EM>不</EM>好的,因为
签入的使用是使用一个允许存取 PPP process的帐号,然後检查帐号密码,该帐号密码是由
RAP 、在 <CODE>/etc/passwd</CODE> 档的帐号和 <CODE>/etc/shadow</CODE> 档的密码供应。
<P>
<P>所以如果我们设定原本版本对每个使用者,如 <CODE>ppp</CODE> 可以在 shell 执行,然後任何人可以
获得 ppp 链结透过设定他们对使用者 <CODE>ppp</CODE> 的 PAP 和 null 的密码。
<P>
<P>我们修正 <CODE>UPAP_AUTHNAK</CODE> 取代
<CODE>UPAP_AUTHACK</CODE> 如果密码栏位是空的。
<P>有趣的是 <CODE>pppd-2.2.0</CODE> 有相同的问题。
<P>接下来我们需要变更 Makefile 以便让两件事发生:
<P><CODE>USE_SHADOW</CODE> 必须被重新定义且<CODE>libshadow.a</CODE> 需要被新增到链结 process。
<P>
<P>编辑 Makefile 且新增:
<BLOCKQUOTE><CODE>
<PRE>
LIBS = -lshadow
</PRE>
</CODE></BLOCKQUOTE>
<P>然後我们找到这一行:
<BLOCKQUOTE><CODE>
<PRE>
COMPILE_FLAGS = -I.. -D_linux_=1 -DGIDSET_TYPE=gid_t
</PRE>
</CODE></BLOCKQUOTE>
<P>然後改变它变成:
<BLOCKQUOTE><CODE>
<PRE>
COMPILE_FLAGS = -I.. -D_linux_=1 -DGIDSET_TYPE=gid_t -DUSE_SHADOW
</PRE>
</CODE></BLOCKQUOTE>
<P>现在执行 make 跟 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>
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions