Linux登錄驗證機制、SSH Bruteforce Login學習


相關學習資料

http://files.cnblogs.com/LittleHann/linux%E4%B8%AD%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E8%AE%A4%E8%AF%81%E6%9C%BA%E5%88%B6%E7%9A%84%E7%A0%94%E7%A9
%B6.rar
http://blog.chinaunix.net/uid-20196318-id-94771.html http://wenku.baidu.com/view/e3c66fdc50e2524de5187eda.html https://www.ibm.com/developerworks/cn/linux/l-pam/ https://www.ibm.com/developerworks/cn/linux/l-pam/#resources http://linux.chinaunix.net/techdoc/beginner/2008/11/17/1045867.shtml https://help.ubuntu.com/10.04/serverguide/kerberos.html http://blog.jobbole.com/22367/ http://www.ibm.com/developerworks/cn/linux/l-radius/ http://www3.imperial.ac.uk/ict/services/security/securityservices/publickeyinfrastructure/installcaonlinux https://wiki.archlinux.org/index.php/S/KEY_Authentication http://en.wikipedia.org/wiki/S/KEY http://blog.chinaunix.net/uid-773723-id-152230.html http://blog.lizhigang.net/archives/249 http://www.360doc.com/content/12/0502/11/9523733_208062914.shtml http://nichael1983.blog.163.com/blog/static/114969433201002711850400/ http://docstore.mik.ua/orelly/networking_2ndEd/ssh/ch11_04.htm http://blog.scottlowe.org/2006/08/21/native-kerberos-authentication-with-ssh/ http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.security/doc/security/using_openssh_with_kerberosv5.htm http://www.slac.stanford.edu/comp/unix/sshGSSAPI.html http://www.linuxmanpages.com/man5/sshd_config.5.php

 

目錄

1. Linux中的登錄驗證機制
2. SSH中的登錄驗證機制
3. SSH Bruteforce Login的相關方法
4. Linux PAM Module Code Example

 

Linux中的登錄驗證機制

談及"登錄驗證"這個概念,小瀚覺得應該要在不同的場景下進行具體討論,Linux中的登錄驗證機制可以分為以下幾類:

1. 系統級的登錄驗證:

系統級的登錄指的是我們登錄Linux系統時顯示的那個login: 提示,要登錄tty終端,我們就必須通過這個登錄。這是一個系統級的登錄驗證(和windows下的winLogin.exe是一個概念)

linux系統里管理用戶及密碼的兩個重要的文件

/etc/passwd
/etc/shadow

/etc/passwd包含各個用戶的信息,linux平台包含七個字段,各個字段間用冒號隔開,分別是:

用戶名:密碼:用戶id:組id:用戶描述:用戶家目錄:用戶的登錄shell
cat /etc/passwd

測試代碼: passwd.c

#include <grp.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main (void)
{
  uid_t me;
  struct passwd *my_passwd;

  /* Get information about the user ID.  */
  me = getuid ();
  my_passwd = getpwuid (me);
  if (!my_passwd)
  {
      printf ("Couldn't find out about user %d.\n", (int) me);
      exit (EXIT_FAILURE);
  }

  /* Print the information.  */
  printf ("My login name is %s.\n", my_passwd->pw_name);
  printf ("My passwd is %s.\n", my_passwd->pw_passwd);
  printf ("My uid is %d.\n", (int) (my_passwd->pw_uid));
  printf ("My gid is %d.\n", (int) (my_passwd->pw_gid));
  printf ("My Real name is %s.\n", my_passwd->pw_gecos);
  printf ("My home directory is %s.\n", my_passwd->pw_dir);
  printf ("My default shell is %s.\n", my_passwd->pw_shell);
 
  return EXIT_SUCCESS;
}

/etc/shadow包含用戶的密碼信息,在linux中包含九項內容,分別是:

用戶登錄名:加密口令:這個時間是從1970年01月01日算起到最近一次修改口令的時間間隔(天數): 兩次修改口令間隔最少的天數;如果設置為0,則禁用此功能: 兩次修改口令間隔最多的天數: 
提前多少天警告用戶口令將過期: 在口令過期之后多少天禁用此用戶: 用戶過期日期: 保留字段,目前為空,以備將來Linux發展之用
cat /etc/shadow

測試代碼: shadow.c

#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <shadow.h>

/*
 * Print information from the password entry
 * about the user name given as argv[1].
 */

int main( int argc, char** argv ) 
{
    struct spwd* sp; 
    if (argc < 2) 
    {
      printf("%s username \n", argv[0]);
      return(EXIT_FAILURE);
    }

    if( ( sp = getspnam( argv[1] ) ) == (struct spwd*)0) 
    {
      fprintf( stderr, "getspnam: unknown %s\n", argv[1] );
      return( EXIT_FAILURE );
    }
    printf( "login name  %s\n", sp->sp_namp );
    printf( "password    %s\n", sp->sp_pwdp );
    printf( "last password change    %d\n", sp->sp_lstchg );
    printf( "days until change allowed    %d\n", sp->sp_min );
    printf( "days before change required    %d\n", sp->sp_max );
    printf( "days warning for expiration    %d\n", sp->sp_warn );
    printf( "days before account inactive    %d\n", sp->sp_inact );
    printf( "date when account expires    %d\n", sp->sp_expire );
    printf( "reserved for future use    %d\n", sp->sp_flag ); 

    return( EXIT_SUCCESS );
}

關於Linux的系統級login登錄驗證的原理學習,請參閱"相關資料中給出的鏈接"

2. 第三方應用程序登錄驗證機制

對於Linux上的很多應用程序(windows上也一樣),應用程序可以自己維護一套身份認證信息庫是很普遍的,這種密碼驗證機制的方式、加密的算法、存儲的方式很大程度上取決於開發軟件的程序員的想法。同時,第三方應用也可以以系統中的核心密碼文件(/etc/passwd、/etc/shadow)作為身份信息庫,這樣,用戶在登錄的時候,需要輸入的就是Linux系統本身的賬戶密碼。總體來說,有一下幾種身份驗證方式

1) 將賬戶信息保存在磁盤的xx.ini配置文件中(加密方式可選)
2) 將賬戶信息保存在本地、或者遠程的數據庫中(在mysql中建立相應的庫、表)
3) 利用Linux自身固有的賬戶密碼文件作為身份信息庫(/etc/passwd、/etc/shadow)(實現方式請參閱1)

3. PAM身份驗證

PAM(插入式驗證模塊(Pluggable Authentication Module,PAM))
簡單來說,就是提供了一組身份驗證、密碼驗證的統一抽象接口,應用程序員可以使用這些API接口來實現與安全性相關的功能,例如:

1) 用戶驗證
2) 數據加密
3) LDAP

相對於傳統的應用系統各自生成自己獨立的身份驗證機制,使用PAM架構,安全性、兼容性、可擴展性都更好,因為PAM機制將多個低級別驗證模式繼承到高級別API中,該API將允許以獨立於底層驗證模式的方式編寫驗證模塊。我們知道,既然PAM的目標是可擴展性、封裝底層實現細節,則它的整體表現基本上會表現為可插拔的模塊的形式,即PAM提供一個承上啟下的基礎環境,向下針對不同的密碼存儲、驗證方式分別進行了模塊實現,向上暴露出的API接口則針對每一種具體的應用封裝了一個API模塊,當某一個應用要使用PAM的時候,只需要動態地加載這個模塊即可。

PAM中的動態驗證配置信息保存在/etc/pam.d 或 /etc/pam.conf中

cat /etc/pam.d/login
#%PAM-1.0
auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so
auth       include      system-auth
account    required     pam_nologin.so
account    include      system-auth
password   include      system-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    optional     pam_keyinit.so force revoke
session    required     pam_loginuid.so
session    include      system-auth
session    optional     pam_console.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open

PAM 模塊的基本流程

顯示 PAM 如何處理配置文件的流程圖

PAM模塊的結構(例如/etc/pam.d/passwd)
PAM 模塊是按模塊類型歸類的。任何給定的模塊至少要實現四種模塊類型功能之一:

1. 驗證模塊(auth): 用於驗證用戶或設置/銷毀憑證
2. 帳戶管理模塊(account): 將執行與訪問、帳戶及憑證有效期、密碼限制/規則等有關的操作
3. 會話管理模塊(session): 用於初始化和終止會話。
4. 密碼管理模塊(password)將執行與密碼更改/更新有關的操作

之前說過,PAM的整體架構是一個承上啟下的架構,在上層是針對不同的應用系統提供不同的動態加載模塊,在/etc/pam.d/xxx中可以對它們進行配置。而在下層,PAM需要封裝對密碼驗證、身份驗證、訪問控制等功能的代碼模塊
PAM將提供不同的功能,例如單點登錄驗證、訪問控制等。每個功能的實現都是由不同的模塊處理的。下面是一些主要模塊:

1. pam_access 將使用登錄名/域名,根據 /etc/security/access.conf 中的預定義規則交付日志守護進程樣式的登錄訪問控制。
2. pam_cracklib 將根據密碼規則檢查密碼。
3. pam_env sets/unsets 環境變量來自 /etc/security/pam_env_conf。
4. pam_debug 將調試 PAM。
5. pam_deny 將拒絕 PAM 模塊。
6. pam_echo 將打印消息。
7. pam_exec 將執行外部命令。
8. pam_ftp 是匿名訪問模塊。
9. pam_localuser 要求將用戶列於 /etc/passwd 中。
10. pam_unix 將通過 /etc/passwd 提供傳統密碼驗證。

4. 基於網絡的中心式身份驗證

基於網絡的中心式身份驗證常常表現為一個中心服務器(中心式的網狀結構),上面保存了所有賬戶的身份信息,應用程序在驗證待登錄用戶的身份時,直接將原始請求發送到中心服務器進行集中式驗證,然后根據驗證結果決定此用戶是否能登錄。

集中式身份認證的技術主要有以下幾種:

1. Kerberos
Kerberos協議主要用於計算機網絡的身份鑒別(Authentication), 其特點是用戶只需輸入一次身份驗證信息就可以憑借此驗證獲得的票據(ticket-granting ticket)訪問多個服務,即SSO
(Single Sign On)。由於在每個Client和Service之間建立了共享密鑰,使得該協議具有相當的安全性 http:
//linux.chinaunix.net/techdoc/beginner/2008/11/17/1045867.shtml https://help.ubuntu.com/10.04/serverguide/kerberos.html 2. RADIUS(Remote Authentication Dial-In User Service) Remote Authentication Dial-In User Service 協議是在 IETF 的 RFC 2865 中定義的。它允許網絡訪問服務器(NAS)執行對用戶的驗證、授權和記帳。RADIUS 是基於 UDP 的一種客戶
機/服務器協議。RADIUS 客戶機是網絡訪問服務器,它通常是一個路由器、交換機或無線訪問點(訪問點是網絡上專門配置的節點;WAP 是無線版本)。RADIUS 服務器通常是在 UNIX 或
Windows 2000 服務器上運行的一個監護程序 功能完整的 RADIUS 服務器可以支持很多不同的用戶驗證機制,包括: 1) LDAP 2) PAP(Password Authentication Protocol,密碼驗證協議,與 PPP 一起使用,在此機制下,密碼以明文形式被發送到客戶機進行比較) 3) CHAP(Challenge Handshake Authentication Protocol,挑戰握手驗證協議,比 PAP 更安全,它同時使用用戶名和密碼) 4) 本地 UNIX/Linux 系統密碼數據庫(/etc/passwd) 5) 其他本地數據庫(Mysql、postgreSQL) http://blog.jobbole.com/22367/ http://www.ibm.com/developerworks/cn/linux/l-radius/ 3. CA(Certificate Authority) CA是一種基於非對稱加密算法的證書服務,CA體制中的"根服務器"就是所謂的中心認證服務器,服務所有子節點的證書頒發、身份認證 http://www3.imperial.ac.uk/ict/services/security/securityservices/publickeyinfrastructure/installcaonlinux

 

SSH中的登錄驗證機制

在基本了解了Linux下的登錄身份驗證后,我們接下來學習一下SSH中都有哪些身份驗證機制。這里所指的SSH都是指在Linux、Unix上普遍使用的openSSH開源軟件

SSH的配置文件所在位置:

/etc/ssh/sshd_config

我們根據它的配置文件來學習SSH中的身份登錄驗證機制

0x1: PasswordAuthentication

這是最常見、普遍的一種SSH登錄驗證機制,在這種驗證模式下,我們在登錄SSH服務器的時候,console的回顯是提示我們輸入用戶名、密碼,並根據真實性決定是否登錄成功,用戶名、密碼的信
息庫來自於Linux自身的賬戶信息庫(/etc/passwd)

0x2: ChallengeResponseAuthentication

顧名思義,挑戰身份驗證模式,類似於微軟的chap協議。openSSH在實現挑戰響應模式的時候采用了S/KEY(one-time one-password)
https://wiki.archlinux.org/index.php/S/KEY_Authentication
http://en.wikipedia.org/wiki/S/KEY
在ssh下配置一次一密S/KEY需要安裝額外的模塊

0x3: RSAAuthentication、PubkeyAuthentication

這就是我們常說的RSA證書登錄機制,或者叫免密碼登錄機制。根據RSA公鑰算法的原理,一對RSA證書分為公鑰證書、私鑰證書。私鑰證書保存在客戶端,用於證明自己的身份,而公鑰證書保存在服
務端,用於加、解密消息 ssh
-client、putty都可以配置RSA證書進行免密碼登錄 http://blog.chinaunix.net/uid-773723-id-152230.html http://blog.lizhigang.net/archives/249 http://www.360doc.com/content/12/0502/11/9523733_208062914.shtml http://nichael1983.blog.163.com/blog/static/114969433201002711850400/ (配置的過程不復雜,注意權限問題即可)

0x4: KerberosAuthentication

KerberosAuthentication是一種中心式的身份認證機制,在ssh上使用KerberosAuthentication認證,需要安裝額外的KerberosAuthentication模塊
http://docstore.mik.ua/orelly/networking_2ndEd/ssh/ch11_04.htm
http://blog.scottlowe.org/2006/08/21/native-kerberos-authentication-with-ssh/
http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.security/doc/security/using_openssh_with_kerberosv5.htm

0x5: GSSAPIAuthentication

GSSAPIAuthentication只能在SSH2協議下使用
http://www.slac.stanford.edu/comp/unix/sshGSSAPI.html

0x6: UsePAM

我們之前學習過,PAM(Pluggable Authentication Module)是一種對底層身份認證代碼邏輯的API封裝,SSH同樣也支持PAM認證
UsePAMEnables the Pluggable Authentication Module
interface. If set to ``yes'' this will enable PAM authentication using
ChallengeResponseAuthentication and PAM account and session module processing for all authentication types. Because PAM challenge-response authentication usually serves an equivalent role to password authentication, you should disable either
PasswordAuthentication or ChallengeResponseAuthentication. If UsePAM
is enabled, you will not be able to run sshd(8) as a non-root user. The default is ``no'' http://www.linuxmanpages.com/man5/sshd_config.5.php cat /etc/pam.d/sshd #%PAM-1.0 auth include system-auth account required pam_nologin.so account include system-auth password include system-auth session optional pam_keyinit.so force revoke session include system-auth session required pam_loginuid.so

關於SSH的這幾種密碼驗證機制,我在本地實驗的時候總結了一下它們的順序

1. SSH服務器"開啟"了PAM驗證: UsePAM=yes
    1) SSH服務器"開啟"了交互式密碼驗證: PasswordAuthentication=yes
        1.1) 證書的RSA私鑰錯誤: 服務器提示進行PAM驗證
        1.2) 證書的RSA私鑰正確: 登錄成功
    2) SSH服務器"關閉"了交互式密碼驗證: PasswordAuthentication=no
        2.1) 證書的RSA私鑰錯誤: 服務器提示進行PAM驗證
        2.2) 證書的RSA私鑰正確: 登錄成功
2. SSH服務器"關閉"了PAM驗證: UsePAM=no
    1) SSH服務器"開啟"了交互式密碼驗證: PasswordAuthentication=yes
        1.1) 證書的RSA私鑰錯誤: 服務器提示進行交互式密碼驗證
        1.2) 證書的RSA私鑰正確: 登錄成功
    2) SSH服務器"關閉"了交互式密碼驗證: PasswordAuthentication=no
        1.1) 證書的RSA私鑰錯誤: 服務器提示登錄失敗: Permission denied (publickey,gssapi-with-mic,password,keyboard-interactive)
        1.2) 證書的RSA私鑰正確: 登錄成功

綜上來看,可以知道,PAM驗證是優先於PasswordAuthentication驗證進行的(前提是當證書RSA私鑰錯誤的時候)

 

SSH Bruteforce Login的相關方法

SSH的暴力破解,或者說所有系統的暴力破解都有兩個思考方向:

1. 基於字典、詞組組合進行正常流程的窮舉: 速度較慢、且容易受到爆破鎖定防御的影響
2. 從目標開源系統的源代碼下手,利用信息泄漏、PRNG偽隨機漏洞進行算法攻擊

1. 窮舉

https://github.com/addthis/hydra
http://projecthydra.org/

2. 算法攻擊

http://www.exploit-db.com/exploits/5720/

 

4. Linux PAM Module Code Example

0x1: Sample PAM Application

The following is a minimal implementation of su(1) using PAM. Note that it uses the OpenPAM-specific openpam_ttyconv(3) conversation function, which is prototyped in security/openpam.h. If you wish build this application on a system with a different PAM library, you will have to provide your own conversation function. A robust conversation function is surprisingly difficult to implement; the one presented in Appendix C, Sample PAM Conversation Function is a good starting point, but should not be used in real-world applications.

/*-
 * Copyright (c) 2002,2003 Networks Associates Technology, Inc.
 * All rights reserved.
 *
 * This software was developed for the FreeBSD Project by ThinkSec AS and
 * Network Associates Laboratories, the Security Research Division of
 * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
 * ("CBOSS"), as part of the DARPA CHATS research program.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $P4: //depot/projects/openpam/bin/su/su.c#10 $
 * $FreeBSD: head/en_US.ISO8859-1/articles/pam/su.c 38826 2012-05-17 19:12:14Z hrs $
 */

#include <sys/param.h>
#include <sys/wait.h>

#include <err.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>

#include <security/pam_appl.h>
#include <security/openpam.h>    /* for openpam_ttyconv() */

extern char **environ;

static pam_handle_t *pamh;
static struct pam_conv pamc;

static void
usage(void)
{

    fprintf(stderr, "Usage: su [login [args]]\n");
    exit(1);
}

int
main(int argc, char *argv[])
{
    char hostname[MAXHOSTNAMELEN];
    const char *user, *tty;
    char **args, **pam_envlist, **pam_env;
    struct passwd *pwd;
    int o, pam_err, status;
    pid_t pid;

    while ((o = getopt(argc, argv, "h")) != -1)
        switch (o) {
        case 'h':
        default:
            usage();
        }

    argc -= optind;
    argv += optind;

    if (argc > 0) {
        user = *argv;
        --argc;
        ++argv;
    } else {
        user = "root";
    }

    /* initialize PAM */
    pamc.conv = &openpam_ttyconv;
    pam_start("su", user, &pamc, &pamh);

    /* set some items */
    gethostname(hostname, sizeof(hostname));
    if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
        goto pamerr;
    user = getlogin();
    if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
        goto pamerr;
    tty = ttyname(STDERR_FILENO);
    if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
        goto pamerr;

    /* authenticate the applicant */
    if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)
        goto pamerr;
    if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
        pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
    if (pam_err != PAM_SUCCESS)
        goto pamerr;

    /* establish the requested credentials */
    if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
        goto pamerr;

    /* authentication succeeded; open a session */
    if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
        goto pamerr;

    /* get mapped user name; PAM may have changed it */
    pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
    if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
        goto pamerr;

    /* export PAM environment */
    if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
        for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
            putenv(*pam_env);
            free(*pam_env);
        }
        free(pam_envlist);
    }

    /* build argument list */
    if ((args = calloc(argc + 2, sizeof *args)) == NULL) {
        warn("calloc()");
        goto err;
    }
    *args = pwd->pw_shell;
    memcpy(args + 1, argv, argc * sizeof *args);

    /* fork and exec */
    switch ((pid = fork())) {
    case -1:
        warn("fork()");
        goto err;
    case 0:
        /* child: give up privs and start a shell */

        /* set uid and groups */
        if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
            warn("initgroups()");
            _exit(1);
        }
        if (setgid(pwd->pw_gid) == -1) {
            warn("setgid()");
            _exit(1);
        }
        if (setuid(pwd->pw_uid) == -1) {
            warn("setuid()");
            _exit(1);
        }
        execve(*args, args, environ);
        warn("execve()");
        _exit(1);
    default:
        /* parent: wait for child to exit */
        waitpid(pid, &status, 0);

        /* close the session and release PAM resources */
        pam_err = pam_close_session(pamh, 0);
        pam_end(pamh, pam_err);

        exit(WEXITSTATUS(status));
    }

pamerr:
    fprintf(stderr, "Sorry\n");
err:
    pam_end(pamh, pam_err);
    exit(1);
}

0x2: Sample PAM Module

The following is a minimal implementation of pam_unix(8), offering only authentication services. It should build and run with most PAM implementations, but takes advantage of OpenPAM extensions if available: note the use of pam_get_authtok(3), which enormously simplifies prompting the user for a password.

/*-
 * Copyright (c) 2002 Networks Associates Technology, Inc.
 * All rights reserved.
 *
 * This software was developed for the FreeBSD Project by ThinkSec AS and
 * Network Associates Laboratories, the Security Research Division of
 * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
 * ("CBOSS"), as part of the DARPA CHATS research program.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $P4: //depot/projects/openpam/modules/pam_unix/pam_unix.c#3 $
 * $FreeBSD: head/en_US.ISO8859-1/articles/pam/pam_unix.c 38826 2012-05-17 19:12:14Z hrs $
 */

#include <sys/param.h>

#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <security/pam_modules.h>
#include <security/pam_appl.h>

#ifndef _OPENPAM
static char password_prompt[] = "Password:";
#endif

#ifndef PAM_EXTERN
#define PAM_EXTERN
#endif

PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags,
    int argc, const char *argv[])
{
#ifndef _OPENPAM
    struct pam_conv *conv;
    struct pam_message msg;
    const struct pam_message *msgp;
    struct pam_response *resp;
#endif
    struct passwd *pwd;
    const char *user;
    char *crypt_password, *password;
    int pam_err, retry;

    /* identify user */
    if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
        return (pam_err);
    if ((pwd = getpwnam(user)) == NULL)
        return (PAM_USER_UNKNOWN);

    /* get password */
#ifndef _OPENPAM
    pam_err = pam_get_item(pamh, PAM_CONV, (const void **)&conv);
    if (pam_err != PAM_SUCCESS)
        return (PAM_SYSTEM_ERR);
    msg.msg_style = PAM_PROMPT_ECHO_OFF;
    msg.msg = password_prompt;
    msgp = &msg;
#endif
    for (retry = 0; retry < 3; ++retry) {
#ifdef _OPENPAM
        pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
            (const char **)&password, NULL);
#else
        resp = NULL;
        pam_err = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr);
        if (resp != NULL) {
            if (pam_err == PAM_SUCCESS)
                password = resp->resp;
            else
                free(resp->resp);
            free(resp);
        }
#endif
        if (pam_err == PAM_SUCCESS)
            break;
    }
    if (pam_err == PAM_CONV_ERR)
        return (pam_err);
    if (pam_err != PAM_SUCCESS)
        return (PAM_AUTH_ERR);

    /* compare passwords */
    if ((!pwd->pw_passwd[0] && (flags & PAM_DISALLOW_NULL_AUTHTOK)) ||
        (crypt_password = crypt(password, pwd->pw_passwd)) == NULL ||
        strcmp(crypt_password, pwd->pw_passwd) != 0)
        pam_err = PAM_AUTH_ERR;
    else
        pam_err = PAM_SUCCESS;
#ifndef _OPENPAM
    free(password);
#endif
    return (pam_err);
}

PAM_EXTERN int
pam_sm_setcred(pam_handle_t *pamh, int flags,
    int argc, const char *argv[])
{

    return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
    int argc, const char *argv[])
{

    return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_open_session(pam_handle_t *pamh, int flags,
    int argc, const char *argv[])
{

    return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_close_session(pam_handle_t *pamh, int flags,
    int argc, const char *argv[])
{

    return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t *pamh, int flags,
    int argc, const char *argv[])
{

    return (PAM_SERVICE_ERR);
}

#ifdef PAM_MODULE_ENTRY
PAM_MODULE_ENTRY("pam_unix");
#endif

0x3: Sample PAM Conversation Function

The conversation function presented below is a greatly simplified version of OpenPAM's openpam_ttyconv(3). It is fully functional, and should give the reader a good idea of how a conversation function should behave, but it is far too simple for real-world use. Even if you are not using OpenPAM, feel free to download the source code and adapt openpam_ttyconv(3) to your uses; we believe it to be as robust as a tty-oriented conversation function can reasonably get.

/*-
 * Copyright (c) 2002 Networks Associates Technology, Inc.
 * All rights reserved.
 *
 * This software was developed for the FreeBSD Project by ThinkSec AS and
 * Network Associates Laboratories, the Security Research Division of
 * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
 * ("CBOSS"), as part of the DARPA CHATS research program.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: head/en_US.ISO8859-1/articles/pam/converse.c 38826 2012-05-17 19:12:14Z hrs $
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <security/pam_appl.h>

int
converse(int n, const struct pam_message **msg,
    struct pam_response **resp, void *data)
{
    struct pam_response *aresp;
    char buf[PAM_MAX_RESP_SIZE];
    int i;

    data = data;
    if (n <= 0 || n > PAM_MAX_NUM_MSG)
        return (PAM_CONV_ERR);
    if ((aresp = calloc(n, sizeof *aresp)) == NULL)
        return (PAM_BUF_ERR);
    for (i = 0; i < n; ++i) {
        aresp[i].resp_retcode = 0;
        aresp[i].resp = NULL;
        switch (msg[i]->msg_style) {
        case PAM_PROMPT_ECHO_OFF:
            aresp[i].resp = strdup(getpass(msg[i]->msg));
            if (aresp[i].resp == NULL)
                goto fail;
            break;
        case PAM_PROMPT_ECHO_ON:
            fputs(msg[i]->msg, stderr);
            if (fgets(buf, sizeof buf, stdin) == NULL)
                goto fail;
            aresp[i].resp = strdup(buf);
            if (aresp[i].resp == NULL)
                goto fail;
            break;
        case PAM_ERROR_MSG:
            fputs(msg[i]->msg, stderr);
            if (strlen(msg[i]->msg) > 0 &&
                msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                fputc('\n', stderr);
            break;
        case PAM_TEXT_INFO:
            fputs(msg[i]->msg, stdout);
            if (strlen(msg[i]->msg) > 0 &&
                msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
                fputc('\n', stdout);
            break;
        default:
            goto fail;
        }
    }
    *resp = aresp;
    return (PAM_SUCCESS);
 fail:
        for (i = 0; i < n; ++i) {
                if (aresp[i].resp != NULL) {
                        memset(aresp[i].resp, 0, strlen(aresp[i].resp));
                        free(aresp[i].resp);
                }
        }
        memset(aresp, 0, n * sizeof *aresp);
    *resp = NULL;
    return (PAM_CONV_ERR);

Relevant Link:

https://www.freebsd.org/doc/en_US.ISO8859-1/articles/pam/article.html

 

Copyright (c) 2014 LittleHann All rights reserved

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM