2011-05-06 13 views
8

私は、ワイヤを通じて非同期にユーザー名/パスワード要求を受け取るレガシーアプリケーションを持っています。私はすでにユーザ名とパスワードを変数として保存しているので、Linux(Pian)のPAMで認証する最良の方法は何でしょうか?レガシーアプリケーションのPAM認証

私は自分の会話機能を書こうとしましたが、パスワードを取得する最善の方法がわかりません。私はappdataに格納し、それをpam_conv構造体から参照することを検討しましたが、それを行う方法に関するドキュメントはほとんどありません。

会話機能の過度な負荷がない状態でユーザーを認証する簡単な方法はありますか?私はpam_set_dataをうまく使用することができず、それが適切であるかどうかはわかりません。会話機能で

user = guiMessage->username; 
pass = guiMessage->password; 

pam_handle_t* pamh = NULL; 
int   pam_ret; 
struct pam_conv conv = { 
    my_conv, 
    NULL 
}; 

pam_start("nxs_login", user, &conv, &pamh); 
pam_ret = pam_authenticate(pamh, 0); 

if (pam_ret == PAM_SUCCESS) 
    permissions = 0xff; 

pam_end(pamh, pam_ret); 

そして、最初の試みは(パスワードはテストのためにハードコードされている)の結果:

int 
my_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *data) 
{ 
    struct pam_response *aresp; 

    if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG) 
    return (PAM_CONV_ERR); 
    if ((aresp = (pam_response*)calloc(num_msg, sizeof *aresp)) == NULL) 
    return (PAM_BUF_ERR); 
    aresp[0].resp_retcode = 0; 
    aresp[0].resp = strdup("mypassword"); 

    *resp = aresp; 
    return (PAM_SUCCESS); 
} 

任意の助けをいただければ幸いです。ここ

は私がやっているものです。ありがとうございました!

答えて

12

これは私がやったことです。 3つのアスタリスクでマークされたコメントを参照してください。

#include <stdlib.h> 
#include <iostream> 
#include <fstream> 
#include <security/pam_appl.h> 
#include <unistd.h> 

// To build this: 
// g++ test.cpp -lpam -o test 

struct pam_response *reply; 

//function used to get user input 
int function_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) 
{ 
    *resp = reply; 
    return PAM_SUCCESS; 
} 

int main(int argc, char** argv) 
{ 
    if(argc != 2) { 
     fprintf(stderr, "Usage: check_user <username>\n"); 
     exit(1); 
    } 
    const char *username; 
    username = argv[1]; 

    const struct pam_conv local_conversation = { function_conversation, NULL }; 
    pam_handle_t *local_auth_handle = NULL; // this gets set by pam_start 

    int retval; 

    // local_auth_handle gets set based on the service 
    retval = pam_start("common-auth", username, &local_conversation, &local_auth_handle); 

    if (retval != PAM_SUCCESS) 
    { 
    std::cout << "pam_start returned " << retval << std::endl; 
    exit(retval); 
    } 

    reply = (struct pam_response *)malloc(sizeof(struct pam_response)); 

    // *** Get the password by any method, or maybe it was passed into this function. 
    reply[0].resp = getpass("Password: "); 
    reply[0].resp_retcode = 0; 

    retval = pam_authenticate(local_auth_handle, 0); 

    if (retval != PAM_SUCCESS) 
    { 
    if (retval == PAM_AUTH_ERR) 
    { 
     std::cout << "Authentication failure." << std::endl; 
    } 
    else 
    { 
     std::cout << "pam_authenticate returned " << retval << std::endl; 
    } 
    exit(retval); 
    } 

    std::cout << "Authenticated." << std::endl; 

    retval = pam_end(local_auth_handle, retval); 

    if (retval != PAM_SUCCESS) 
    { 
    std::cout << "pam_end returned " << retval << std::endl; 
    exit(retval); 
    } 

    return retval; 
} 
+0

ありがとうございました!そして、ここで私は、会話機能を、バイパスして、その外の応答を使って作業するのではなく、その通信機能に触れる方法を見つけようとしていました。 –

+0

これは 'root'(単に 'root'、他のすべてのユーザーは認証済みです)では機能しません。それはバグですか? – alexandernst

+0

私は分かりません。私は根っこをしなかった。定期的にルートパスワードを使用する必要がある場合は、おそらく何か間違っているでしょう。 – Fantius

1

(パスワードなど)の標準的な情報は、PAMのために渡される方法は、(は、pam_set_itemのmanページを参照してください)は、pam_set_itemとPAMハンドルに設定された変数を使用することです。

アプリケーションが後でpam_stackに使用する必要があるものを設定できます。

pam_handle_t* handle = NULL; 
pam_start("common-auth", username, NULL, &handle); 
pam_set_item(handle, PAM_AUTHTOK, password); 

これは、パスワードを行います:あなたはpam_stackにパスワードを入れたい場合は、すぐ下の擬似コードに似たスタックにPAM_AUTHTOK変数を設定することによりに、pam_start()を呼び出した後にそれを行うことができるはずですそれを使用するモジュールにスタック上で利用可能ですが、通常は、サービスのpam_configurationで標準のuse_first_passまたはtry_first_passオプションを設定することによってモジュールに使用するように指示する必要があります(この場合は/etc/pam.d/共通認証)。

標準のpam_unixモジュールはtry_first_passをサポートしているため、システム上のpam設定(pam_unixの行末)にpam_unixモジュールを追加しても問題ありません。

common-authサービスから呼び出されたpam_authenticate()のいずれかの呼び出しは、パスワードを選択して使用するだけで済みます。

use_first_passとtry_first_passの違いについてのちょっとした注意:pam_stackでパスワードを試すようにモジュール(この場合はpam_unix)に指示しますが、password/AUTHTOKが利用できないときは動作が異なります。欠落している場合、use_first_passは失敗し、try_first_passはモジュールにパスワードの入力を要求します。

+0

http://pubs.opengroup.org/onlinepubs/8329799/chap4.htm#tagcjh_05_02_01_01は、 'PAM_AUTHTOK'は「PAMモジュールのみで利用可能であり、アプリケーションでは利用できません」と述べています。だから、あなたが説明したことをすることはできないはずです。あなたはそれが動作するかどうかチェックしましたか?多分それは可能ですが、移植性がありませんか? –

+0

さらに、 'pam_set_item'ドキュメント(http://pubs.opengroup.org/onlinepubs/8329799/pam_set_item.htm#tagmref_pam_set_item)は、' PAM_AUTHOK'を提供している間にその条件を繰り返すようには見えません。 –

0

ファンティウスの解決策は私のために働いていました。

私はもともとJohnの解決法を選択しました。それは、より洗練され、会話機能なしでPAM変数を使用していました(実際にはここでは必要ありません)。しかし、動作しなかったし、動作しません。 Adam Baduraが両方の記事で触れたように、PAMはPAM_AUTHTOKの直接設定を防ぐための内部チェックをいくつか行っています。

Johnのソリューションでは、hereと同様の動作が発生します(pam_conv変数を宣言しても、定義しなくてもログインできるようになります)。

mallocの配置を気にすることをお勧めします。これはアプリケーションによって異なる可能性があります(上記のコードはテスト/テン​​プレートのほうが多かったことに注意してください)。

+0

これは質問に対する答えを提供しません。十分な[評判](https://stackoverflow.com/help/whats-reputation)があれば、[投稿にコメントする]ことができます(https://stackoverflow.com/help/privileges/comment)。代わりに、[質問者からの明確化を必要としない回答を提供する](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-c​​an- i-do-代わりに)。 - [レビューから](/レビュー/低品質の投稿/ 18803902) – Umair

+0

答えとして「ありがとう」を追加しないでください。代わりに、あなたが参考にした答えを投票してください。 - [レビューの投稿](レビュー/低品質の投稿/ 18803902) – Graham

+0

なぜ私はこれらのサイトでカジュアルなのか思い出してくれてありがとう、)私の謝罪! – gagan

関連する問題