使用curl编译PAM模块的目标文件

时间:2014-10-08 18:23:41

标签: c gcc curl pam

我正在编写PAM模块,每次用户登录时我都需要执行https请求。我已经使用curl实现了,但问题是我只要在我的C代码中引入curl include,模块停止工作。

以下是我用来编译它的命令:

  

gcc -fPIC -fno-stack-protector -c mypam.c

     

sudo ld -x --shared -o /lib/x86_64-linux-gnu/security/mypam.so mypam.o

它编译没有问题,但pam模块没有被解释。 如果我删除卷曲部分它工作正常(我添加了必要的行使用mypam.so

我认为问题在于gcc,我并没有表明我想要使用CURL。我试过了gcc -fPIC -fno-stack-protector -c mypam.c -lcurl,但它抱怨道:

mypam.c: In function ‘pam_sm_authenticate’: mypam.c:593:2: error: unknown type name ‘pr’

知道发生了什么事吗?如果我使用main函数将其编译为普通程序并使用命令:gcc -ggdb -Wall -Wextra -o fo fo.c -lcrypto -lm -lcurl它可以正常工作。

CODE:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <security/pam_ext.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


#include <curl/curl.h>

void foo(void){
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();

    // If I just put here a printf("Hello!");  it works
}


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

/* expected hook, this is where custom stuff happens */
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ) {
    int retval;
    const char* pUsername;

    retval = pam_get_user(pamh, &pUsername, "Username: ");

    printf("Welcome %s\n", pUsername);
    foo();

    if (retval != PAM_SUCCESS) {
        return retval;
    }

    return PAM_AUTHINFO_UNAVAIL;
}

正如您所看到的,代码非常简单。如果我只包括curl它可以工作,但如果我在curl库中引用任何东西(因为CURL *curl;它会中断)。 任何的想法? 谢谢!

2 个答案:

答案 0 :(得分:0)

嗯,你没有用libpam链接一件事,所以这将成为一个问题。一般来说,我喜欢通过倾斜测试pam模块,然后查找模块期望的符号与dlsym。这基本上是pam库在配置pam.conf时所做的事情。它找到了库并对其进行了调整并寻找给定的符号。所以这里有一些可以在编译的pam模块上运行的测试代码。

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char* argv[])
{
    if ( argc != 2 )
    {
            printf("Usage: ./dlopentest <path_to_pam_module>\n");
            exit(1);
    }
    void *libhandle = dlopen(argv[1], RTLD_NOW);
    if ( libhandle == NULL )
    {
            printf("%s",dlerror());
            exit(1);
    }
    void* sym = dlsym(libhandle,"pam_sm_authenticate");
    if ( sym == NULL )
    {
            printf("%s",dlerror());
            exit(1);
    }
    sym = dlsym(libhandle,"pam_sm_setcred");
    if ( sym == NULL )
    {
            printf("%s",dlerror());
            exit(1);
    }
    dlclose(libhandle);
}

显然并非所有的pam_sm_ *符号都经过测试,只需测试您希望模块具有的那些符号。

使用-ldl构建并链接它,然后在pam模块共享对象上运行它。在pam.conf中配置模块后,它应该详细地抱怨导致模块无法加载的任何内容。这非常容易调试,并且可以很容易地结合到单元测试中。我会向正在开发一个严重的pam模块的人推荐这种“dlopentest”。

答案 1 :(得分:0)

我也有这个问题。 作为一种解决方法,我将我的cURL相关函数与pam模块分开。 现在,pam模块使用cURL执行程序并处理结果代码, 像:

char *my_args[5];
pid_t pid;

my_args[0] = "myprogram_with_curl";
my_args[1] = pUsername;
my_args[2] = pPassword;
my_args[3] = NULL;

pid = fork();
int status;
if (pid) //retrieve result from myprogram_with_curl
{
  pid = waitpid(pid, &status, 0);
  if (status != 0)
  {
    return PAM_AUTH_ERR;
  } 
}
else
{
  execv("/usr/bin/myprogram_with_curl", my_args);
  printf("sad! execv failed\n"); 
}