歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> 關於Unix

LinuxShadow-Password-HOWTO-8.加入shadow支援

新增支援shadow程式事實上是很直接的。唯一的問題是程式需要以root(或SUIDroot)權限執行,這樣才可以存取/etc/shadow檔。 這顯示一個大問題:當建立SUID程式時需要很小心依照程式運作。舉例說明:如果以個程式有shellescape,如果程式本身是SUIDroot將不需要
新增支援 shadow 程式事實上是很直接的。 唯一的問題是程式需要以 root (或 SUID root) 權限執行,這樣才可以存取 /etc/shadow 檔。 

這顯示一個大問題: 當建立 SUID 程式時需要很小心依照程式運作。舉例說明: 如果以個程式有 shell escape,如果程式本身是 SUID root 將不需要以 root 方式呈現。 

對程式新增支援 shadow 而言,它可以檢查密碼,但不需以 root 權限執行,而是以 SUID shadow 取代執行比較安全。 xlock 程式就是一個例子。 

接下來□例介紹, pppd-1.2.1d 已經以 SUID as root 方式執行,所以新增 shadow 支援應該不會使程式產生任何影響。 



8.1 標頭檔(Header files) 
標頭檔應存在 /usr/include/shadow。 應該有一個 /usr/include/shadow.h檔,但是它將 symbolic link 到 /usr/include/shadow/shadow.h。 

為了新增支援 shadow 程式,你需要 include 標頭檔: 


#include 
#include 



8.2 libshadow.a 函式庫(library) 
當你安裝 Shadow Suite, libshadow.a 檔被建立和安裝在 /usr/lib 目錄。 

當編譯一個 shadow support 程式,linker 需要包括 libshadow.a 函式庫進入鏈結。 


執行如下: 

gcc program.c -o program -lshadow

然而,就像我們接下來要看的例子,大部分大程式使用 Makefile 且通常有變數呼叫 LIBS=... 需要被修改。 


8.3 Shadow 結構(Structure) 
libshadow.a 函式庫對它從 /etc/shadow 檔接收資訊使用結構化呼叫。這是從 /usr/include/shadow/shadow.h 標頭檔的 spwd 結構定義: 



--------------------------------------------------------------------------------

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 */
};


--------------------------------------------------------------------------------

Shadow Suite 可以放除了編碼密碼之外的資料到 sp_pwdp 欄位。密碼欄位可包括: 

username:Npge08pfz4wuk;@/sbin/extra:9479:0:10000::::

這表示一個額外的密碼, /sbin/extra 程式應該被更多的權限呼叫。 程式的呼叫需取得使用者名稱和指出為何需被呼叫的 switch才可通過。 查看 /usr/include/shadow/pwauth.h 和原始碼 pwauth.c 獲得更多資訊。 

為何我們應使用 pwauth 去表示真正的權限,這是什麽意思,它將使第二組權限也跑得很好。 

Shadow Suite 作者指出因為大部分存在的程式都不這麽作羅,所以 Shadow Suite未來的版本將移除。 


8.4 Shadow 函式(Functions) 
shadow.h 包含 libshadow.a 函式庫: 


--------------------------------------------------------------------------------

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));


--------------------------------------------------------------------------------

我們將使用的□例程式是: getspnam 將對供應名稱恢復對我們 spwd 結構。 


8.5 □例 
這是一個□例描述新增 shadow 支援程式,但預設值並沒有。 


本□例使用 Point-to-Point Protocol Server (pppd-1.2.1d),它有個模式是表示 從 /etc/passwd 檔取代 PAP 或 CHAP 檔使用帳號密碼的 PAP 權限,你將不需要在 pppd-2.2.0 加這些程式碼,因為它已經存在羅。 



pppd 的未來大致上不會被使用很多,但是如果你安裝 Shadow Suite,儲存在 /etc/passwd 檔的密碼將無法運作。 

在 pppd-1.2.1d 權限使用的程式碼是位在 /usr/src/pppd-1.2.1d/pppd/auth.c 檔。 

接下來程式碼需要被加在所有其他 #include 指令檔案的最上頭,我們將注意有環境指令的 #includes。 



--------------------------------------------------------------------------------

#ifdef HAS_SHADOW
#include 
#include 
#endif


--------------------------------------------------------------------------------

接下來要做的事情是變更實際碼, 我們將變更 auth.c 檔。 

變更前 auth.c 檔 function 為: 


--------------------------------------------------------------------------------

/*
 * 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);
}


--------------------------------------------------------------------------------

使用者的密碼被放在 pw->pw_passwd,所以我們需新增 getspnam function,這將會把密碼放到 spwd->sp_pwdp。 

我們將新增 pwauth function 來表示真正的權限。 這將在 shadow 檔設定時自動產生第二個權限。 

變更為可以支援 shadow 後的 auth.c function: 



--------------------------------------------------------------------------------

/*
 * 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);
}


--------------------------------------------------------------------------------

嚴謹的□例將啟發我們在作其他改變的幫助。 原始的版本如果在 /etc/passwd 檔沒有任何密碼,可允許存取傳回的 UPAP_AUTHACK 。這是不好的,因為簽入的使用是使用一個允許存取 PPP process的帳號,然後檢查帳號密碼,該帳號密碼是由 RAP 、在 /etc/passwd 檔的帳號和 /etc/shadow 檔的密碼供應。 


所以如果我們設定原本版本對每個使用者,如 ppp 可以在 shell 執行,然後任何人可以獲得 ppp 鏈結透過設定他們對使用者 ppp 的 PAP 和 null 的密碼。 


我們修正 UPAP_AUTHNAK 取代 UPAP_AUTHACK 如果密碼欄位是空的。 

有趣的是 pppd-2.2.0 有相同的問題。 

接下來我們需要變更 Makefile 以便讓兩件事發生: 

USE_SHADOW 必須被重新定義且libshadow.a 需要被新增到鏈結 process。 


編輯 Makefile 且新增: 

LIBS = -lshadow

然後我們找到這一行: 

COMPILE_FLAGS = -I.. -D_linux_=1 -DGIDSET_TYPE=gid_t

然後改變它變成: 

COMPILE_FLAGS = -I.. -D_linux_=1 -DGIDSET_TYPE=gid_t -DUSE_SHADOW

現在執行 make 跟 install. 

Copyright © Linux教程網 All Rights Reserved