How to retrieve OID value using Net SNMP in C? - c

I am new to this. I am trying to use Net-SNMP's snmpget file to retrieve an OID and store it in a variable. Where can I specify the IP address of the device I am querying? Where can I specify what OID I am looking for? And how can I store the value of the OID?
I already know the IP address of my device and the OID I am looking for.
Here is the code Net-SNMP provides for snmpget:
#include <net-snmp/net-snmp-config.h>
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <sys/types.h>
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include <stdio.h>
#include <ctype.h>
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#if HAVE_NETDB_H
#include <netdb.h>
#endif
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <net-snmp/utilities.h>
#include <net-snmp/net-snmp-includes.h>
#define NETSNMP_DS_APP_DONT_FIX_PDUS 0
static void
optProc(int argc, char *const *argv, int opt)
{
switch (opt) {
case 'C':
while (*optarg) {
switch (*optarg++) {
case 'f':
netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
NETSNMP_DS_APP_DONT_FIX_PDUS);
break;
default:
fprintf(stderr, "Unknown flag passed to -C: %c\n",
optarg[-1]);
exit(1);
}
}
break;
}
}
void
usage(void)
{
fprintf(stderr, "USAGE: snmpget ");
snmp_parse_args_usage(stderr);
fprintf(stderr, " OID [OID]...\n\n");
snmp_parse_args_descriptions(stderr);
fprintf(stderr,
" -C APPOPTS\t\tSet various application specific behaviours:\n");
fprintf(stderr,
"\t\t\t f: do not fix errors and retry the request\n");
}
int
main(int argc, char *argv[])
{
netsnmp_session session, *ss;
netsnmp_pdu *pdu;
netsnmp_pdu *response;
netsnmp_variable_list *vars;
int arg;
int count;
int current_name = 0;
char *names[SNMP_MAX_CMDLINE_OIDS];
oid name[MAX_OID_LEN];
size_t name_length;
int status;
int failures = 0;
int exitval = 0;
/*
* get the common command line arguments
*/
switch (arg = snmp_parse_args(argc, argv, &session, "C:", optProc)) {
case NETSNMP_PARSE_ARGS_ERROR:
exit(1);
case NETSNMP_PARSE_ARGS_SUCCESS_EXIT:
exit(0);
case NETSNMP_PARSE_ARGS_ERROR_USAGE:
usage();
exit(1);
default:
break;
}
if (arg >= argc) {
fprintf(stderr, "Missing object name\n");
usage();
exit(1);
}
if ((argc - arg) > SNMP_MAX_CMDLINE_OIDS) {
fprintf(stderr, "Too many object identifiers specified. ");
fprintf(stderr, "Only %d allowed in one request.\n", SNMP_MAX_CMDLINE_OIDS);
usage();
exit(1);
}
/*
* get the object names
*/
for (; arg < argc; arg++)
names[current_name++] = argv[arg];
SOCK_STARTUP;
/*
* Open an SNMP session.
*/
ss = snmp_open(&session);
if (ss == NULL) {
/*
* diagnose snmp_open errors with the input netsnmp_session pointer
*/
snmp_sess_perror("snmpget", &session);
SOCK_CLEANUP;
exit(1);
}
/*
* Create PDU for GET request and add object names to request.
*/
pdu = snmp_pdu_create(SNMP_MSG_GET);
for (count = 0; count < current_name; count++) {
name_length = MAX_OID_LEN;
if (!snmp_parse_oid(names[count], name, &name_length)) {
snmp_perror(names[count]);
failures++;
} else
snmp_add_null_var(pdu, name, name_length);
}
if (failures) {
snmp_close(ss);
SOCK_CLEANUP;
exit(1);
}
/*
* Perform the request.
*
* If the Get Request fails, note the OID that caused the error,
* "fix" the PDU (removing the error-prone OID) and retry.
*/
retry:
status = snmp_synch_response(ss, pdu, &response);
if (status == STAT_SUCCESS) {
if (response->errstat == SNMP_ERR_NOERROR) {
for (vars = response->variables; vars;
vars = vars->next_variable)
print_variable(vars->name, vars->name_length, vars);
} else {
fprintf(stderr, "Error in packet\nReason: %s\n",
snmp_errstring(response->errstat));
if (response->errindex != 0) {
fprintf(stderr, "Failed object: ");
for (count = 1, vars = response->variables;
vars && count != response->errindex;
vars = vars->next_variable, count++)
/*EMPTY*/;
if (vars) {
fprint_objid(stderr, vars->name, vars->name_length);
}
fprintf(stderr, "\n");
}
exitval = 2;
/*
* retry if the errored variable was successfully removed
*/
if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
NETSNMP_DS_APP_DONT_FIX_PDUS)) {
pdu = snmp_fix_pdu(response, SNMP_MSG_GET);
snmp_free_pdu(response);
response = NULL;
if (pdu != NULL) {
goto retry;
}
}
} /* endif -- SNMP_ERR_NOERROR */
} else if (status == STAT_TIMEOUT) {
fprintf(stderr, "Timeout: No Response from %s.\n",
session.peername);
exitval = 1;
} else { /* status == STAT_ERROR */
snmp_sess_perror("snmpget", ss);
exitval = 1;
} /* endif -- STAT_SUCCESS */
if (response)
snmp_free_pdu(response);
snmp_close(ss);
SOCK_CLEANUP;
return exitval;
} /* end main() */

Related

Linux libmodbus multi thread free(): double free detected in tcache 2 Aborted (core dumped)

Hi all im working in linux libmodbus tcpip server client process I am reading the data from 3 different server, when all the server are connected then there is no issues but when i disconnect one server form the network then the following error is thrown.
"free(): double free detected in tcache 2
Aborted (core dumped)"
in the terminal. how do i fix it iam using multithreading here to connect two server simultaniously, the code is as follows
main.c
/*
* Copyright © Stéphane Raimbault <stephane.raimbault#gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <modbus.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// clang-format off
#ifdef _WIN32
# include <winsock2.h>
#else
# include <sys/socket.h>
#endif
/* For MinGW */
#ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL 0
#endif
// clang-format on
//#include "test-server.h"
#include "client-server.h"
pthread_mutex_t lock;
int main(int argc, char *argv[])
{
pthread_t server, client,client1,client2;
pthread_mutex_init(&lock, NULL);
pthread_create(&server, NULL, &server_thread, NULL);
pthread_create(&client, NULL, &client_thread, NULL);
pthread_create(&client1, NULL, &client_1_thread, NULL);
pthread_create(&client2, NULL, &client_2_thread, NULL);
// use_backend = TCP;
// ip_or_device = "192.168.1.200";
// for (;;)
// {
// sleep(0.1);
// }
pthread_join(server, NULL);
pthread_join(client, NULL);
pthread_join(client1, NULL);
pthread_join(client2, NULL);
pthread_mutex_destroy(&lock);
// printf("Quit the loop: %s\n", modbus_strerror(errno));
// if (use_backend == TCP) {
// if (s != -1) {
// close(s);
// }
// }
// modbus_mapping_free(mb_mapping);
// free(query);
// /* For RTU */
// modbus_close(ctx);
// modbus_free(ctx);
return 5;
}
client-server.c
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <modbus.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// clang-format off
#ifdef _WIN32
# include <winsock2.h>
#else
# include <sys/socket.h>
#endif
/* For MinGW */
#ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL 0
#endif
// clang-format on
#include "test-server.h"
#include "client-server.h"
extern pthread_mutex_t lock;
uint16_t CS_Buffer[50];
enum {
TCP,
TCP_PI,
RTU
};
void *server_thread(void *arg)
{
// pthread_mutex_lock(&lock);
int s = -1;
modbus_t *ctx;
modbus_mapping_t *mb_mapping;
int rc;
int i;
int use_backend;
uint8_t *query;
int header_length;
char *ip_or_device;
uint16_t tab_reg[32];
ctx = modbus_new_tcp("192.168.1.200", 1502);
query = malloc(MODBUS_TCP_MAX_ADU_LENGTH);
header_length = modbus_get_header_length(ctx);
modbus_set_debug(ctx, TRUE);
mb_mapping = modbus_mapping_new_start_address(UT_BITS_ADDRESS,
UT_BITS_NB,
UT_INPUT_BITS_ADDRESS,
UT_INPUT_BITS_NB,
UT_REGISTERS_ADDRESS,
UT_REGISTERS_NB_MAX,
UT_INPUT_REGISTERS_ADDRESS,
UT_INPUT_REGISTERS_NB);
if (mb_mapping == NULL) {
fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno));
modbus_free(ctx);
// return -1;
}
/* Examples from PI_MODBUS_300.pdf.
Only the read-only input values are assigned. */
/* Initialize input values that's can be only done server side. */
modbus_set_bits_from_bytes(
mb_mapping->tab_input_bits, 0, UT_INPUT_BITS_NB, UT_INPUT_BITS_TAB);
/* Initialize values of INPUT REGISTERS */
for (i = 0; i < UT_INPUT_REGISTERS_NB; i++) {
mb_mapping->tab_input_registers[i] = UT_INPUT_REGISTERS_TAB[i];
}
// mb_mapping->tab_registers[0] = 0x0b;
printf("Starting Server!\n");
s = modbus_tcp_listen(ctx, 1);
modbus_tcp_accept(ctx, &s);
while(1)
{
do {
rc = modbus_receive(ctx, query);
/* Filtered queries return 0 */
} while (rc == 0);
/* The connection is not closed on errors which require on reply such as
bad CRC in RTU. */
if (rc == -1 && errno != EMBBADCRC) {
/* Quit */
// break;
}
/* Special server behavior to test client */
if (query[header_length] == 0x03) {
/* Read holding registers */
if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 3) ==
UT_REGISTERS_NB_SPECIAL) {
printf("Set an incorrect number of values\n");
MODBUS_SET_INT16_TO_INT8(
query, header_length + 3, UT_REGISTERS_NB_SPECIAL - 1);
} else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
UT_REGISTERS_ADDRESS_SPECIAL) {
printf("Reply to this special register address by an exception\n");
modbus_reply_exception(ctx, query, MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY);
// continue;
} else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE) {
const int RAW_REQ_LENGTH = 5;
uint8_t raw_req[] = {(use_backend == RTU) ? INVALID_SERVER_ID : 0xFF,
0x03,
0x02,
0x00,
0x00};
printf("Reply with an invalid TID or slave\n");
modbus_send_raw_request(ctx, raw_req, RAW_REQ_LENGTH * sizeof(uint8_t));
// continue;
} else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
UT_REGISTERS_ADDRESS_SLEEP_500_MS) {
printf("Sleep 0.5 s before replying\n");
usleep(500000);
} else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS) {
// /* Test low level only available in TCP mode //
///* Catch the reply and send reply byte a byte //
uint8_t req[] = "\x00\x1C\x00\x00\x00\x05\xFF\x03\x02\x00\x00";
int req_length = 11;
int w_s = modbus_get_socket(ctx);
if (w_s == -1) {
fprintf(stderr, "Unable to get a valid socket in special test\n");
// continue;
}
// /* Copy TID
req[1] = query[1];
for (i = 0; i < req_length; i++) {
printf("(%.2X)", req[i]);
usleep(5000);
rc = send(w_s, (const char *) (req + i), 1, MSG_NOSIGNAL);
if (rc == -1) {
// break;
}
}
// continue;
}
}
rc = modbus_reply(ctx, query, rc, mb_mapping);
pthread_mutex_lock(&lock);
mb_mapping->tab_registers[0] = CS_Buffer[0];
printf("Server hoalding reg %u", mb_mapping->tab_registers[0]);
pthread_mutex_unlock(&lock);
if (rc == -1) {
//break;
}
}
modbus_close(ctx);
modbus_free(ctx);
// pthread_mutex_unlock(&lock);
return NULL;
}
void *client_thread(void *arg)
{
modbus_t *ctx;
int rc;
uint16_t tab_reg[32];
while(1)
{
ctx = modbus_new_tcp("192.168.1.153", 502);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
//return -1;
}
rc = modbus_read_registers(ctx, 1, 9, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
}
else {
int i;
for (i=0; i < 2; i++) {
// printf("register...\n");
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
pthread_mutex_lock(&lock);
CS_Buffer[i] = tab_reg[i];
pthread_mutex_unlock(&lock);
}
}
sleep(3);
}
modbus_close(ctx);
modbus_free(ctx);
return NULL;
}
void *client_1_thread(void *arg)
{
modbus_t *ctx;
int rc;
uint16_t tab_reg[32];
while(1)
{
ctx = modbus_new_tcp("192.168.1.153", 503);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
//return -1;
}
rc = modbus_read_registers(ctx, 1, 9, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
}
else {
int i;
for (i=0; i < 2; i++) {
//printf("register...\n");
printf("reg_1[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
pthread_mutex_lock(&lock);
//CS_Buffer[i] = tab_reg[i];
pthread_mutex_unlock(&lock);
}
}
sleep(3);
modbus_close(ctx);
modbus_free(ctx);
}
return NULL;
}
void *client_2_thread(void *arg)
{
modbus_t *ctx;
int rc;
uint16_t tab_reg[32];
while(1)
{
ctx = modbus_new_tcp("192.168.1.153", 504);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
//return -1;
}
rc = modbus_read_registers(ctx, 1, 9, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
}
else {
int i;
for (i=0; i < 2; i++) {
//printf("register...\n");
printf("reg_2[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
pthread_mutex_lock(&lock);
//CS_Buffer[i] = tab_reg[i];
pthread_mutex_unlock(&lock);
}
}
sleep(3);
modbus_close(ctx);
modbus_free(ctx);
}
return NULL;
}
Any thoughts kindly share .. thankyou
I tried to print the error in the terminal when the server is not responding but even that error message is not being printed in the display when the server is disconnected.

error occur when I use getopt() to create options in c programming, can someone tell me where did i done wrong

here is my code down below, the code is incomplete, but the problem is I have set the t as the only option I have for this program, and when i run it with option -t input, it gives me error as following:
./run: invalid option -- 't'
Option error !
there is my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <error.h>
#include <string.h>
#define FALSE 0
#define TRUE 1
#define DEFAULT_SECOND 10
extern int errno;
int errnum;
FILE* fin = NULL;
int main (int argc, char* argv[])
{
int opt;
int tFlag = FALSE;
int defaultFlag = TRUE;
int sec;
while ((opt = getopt(argc,argv,"t:"))!=-1)
{
switch (opt)
{
case 't':
tFlag = TRUE;
defaultFlag = FALSE;
break;
case '?':
Printf("No such option, Now taking Exit...");
exit(EXIT_FAILURE);
default:
break;
}
}
for (int i = 0; i < argc - optind; ++i)
{
fin = fopen(argv[optind + i], "r");
if (fin == NULL)
{
errnum = errno;
fprintf(stderr, "Error opening file: %s\n", strerror(errnum));
exit(1);
}
if (defaultFlag == TRUE)
{
sec = defaultFlag;
}
if (tFlag == TRUE)
{
if((sec = atoi(optarg)==-1))
{
printf("input error!!");
exit(EXIT_FAILURE);
}
}
}
return 0;
}
please tell me if I have wrongfully set the option for -t, if possible please tell me where is the problem.

FIBMAP vs FIEMAP ioctl syscall differences

I coded a little tool to show the number of logical blocks of a file and the physical blocks mapped. Using ictl FIBMAP system call, I'm looking on logical-to-physicaal block mapping. So I used an old FIBMAP ictl syscall. My question is : what are the differences between FIBMAP and FIEMAP ? Do you have some tips to deep further into log-phy mapping from my code ? Furthermore, many logical blocks dont seem to map physical blocks. What is the reason ?
ÉDIT :
So I just learned that FIBMAP needs CAP_SYS_RAWIO, so only for root.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#define UNLESS(X) if (!(X))
#define ARRAY_NUM(X) sizeof(X)/sizeof(*(X))
#define ERROR(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
#define RETURN(msg) do { perror(msg); return errno; } while (0)
#define XFREE(X) (X) do { free(X); X = NULL; } while (0)
int get_blck(int fd, int log_block){
int res;
res = ioctl(fd, FIBMAP, &log_block);
if (res < 0) {
ERROR("ioctl FIBMAP failed !\n");
}
return log_block;
}
/* we get the number of logical blocks */
int get_nbr_blcks(int fd){
struct stat buff;
int res;
res = fstat(fd, &buff);
if (res < 0) {
ERROR("fstat error !\n");
}
return buff.st_blocks;
}
/* We print the physical blocks sorted */
void print_blcks(int fd){
int nbr_blcks;
nbr_blcks = get_nbr_blcks(fd);
if (nbr_blcks < 0) {
ERROR("get_nbr_blcks failed!\n");
}
if (nbr_blcks == 0) {
ERROR("no allocated blocks\n");
} else if (nbr_blcks == 1) {
printf("1 block\n\n");
} else {
printf("%d blocks\n\n", nbr_blcks);
}
for (int i = 0; i < nbr_blcks; i++) {
int phy_blck;
phy_blck = get_blck(fd, i);
if (phy_blck < 0) {
ERROR("get_blck failed!\n");
}
/* many [%d, 0] in my case... Where are they */
//if (!phys_block)
//continue;
printf("[%u, %u] ", i, phy_blck);
}
putchar('\n');
}
int main(int argc, char *argv[])
{
int fd;
UNLESS(argc == 2) {
printf("usage: %s file\n", argv[0]);
return 1;
}
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
RETURN("open failed !\n");
}
print_blcks(fd);
return 0;
}

Authentication error on pam application without asking password

I have an application running on an unprivileged user, but at some point this program needs to run another one as a root, would be nice if I can reuse a configured PAM module, like, su, sudo, login or anyone.
So I am trying to write some code to authenticate the root and run this program using PAM, like sudo does, but I cant ask for password, it needs to be automatic. This unprivileged program in a specific time will have the access to root password.
Tried this example here https://www.netbsd.org/docs/guide/en/chap-pam.html but on pam_authenticate, it always return PAM_AUTH_ERR, I have tried all configured modules on my ubuntu 18.04.
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.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 <grp.h>
#include <assert.h>
#include <string>
#include <vector>
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 = (struct pam_response *) 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));
aresp[i].resp = strdup("mypass");
aresp[i].resp_retcode = 0;
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);
}
static struct pam_conv conv = {
converse,
//misc_conv,
NULL
};
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[64];
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";
}
int pam_status = PAM_SUCCESS;
/* initialize PAM */
//pamc.conv = &openpam_ttyconv;
if ((pam_status = pam_start("passwd", user, &conv, &pamh)) != PAM_SUCCESS)
{
assert(false);
}
/* set some items */
gethostname(hostname, sizeof(hostname));
if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
{
assert(false);
}
user = getlogin();
if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
{
assert(false);
}
tty = ttyname(STDERR_FILENO);
if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
{
assert(false);
}
/* authenticate the applicant */
pam_err = pam_authenticate(pamh, PAM_SILENT);
if (pam_err != PAM_SUCCESS)
{
printf("Pam Error (%d)\n", pam_err);
warn("pam_authenticate");
assert(false);
}
printf("AUTHENTICATED ;-)");
assert(false);
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)
{
assert(false);
}
/* establish the requested credentials */
if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
{
assert(false);
}
/* authentication succeeded; open a session */
if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
{
assert(false);
}
/* 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)
{
assert(false);
}
/* 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);
}
std::vector<std::string> arguments;
arguments.resize(argc + 2);
char * args_ptr [arguments.size()];
arguments[0] = pwd->pw_shell;
args_ptr[argc +1] = NULL;
args_ptr[0] = (char *)arguments[0].c_str();
for (int i = 0; i < argc; i++)
{
arguments[i + 1] = argv[i];
args_ptr[i+1] = (char *)arguments[i+1].c_str();
}
/* 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_ptr[0], args_ptr, environ);
warn("execve()");
_exit(1);
pamerr:
fprintf(stderr, "Sorry\n");
err:
pam_end(pamh, pam_err);
exit(1);
}
I expect to fork in a elevated child and run my new program, without asking for password.

Video for Linux two poll returning POLLERR with errno EINVAL

I'v written a simple C shared object library which calls v4l2(Video for Linux two) API e.g. v4l2_open(). Then I'm trying to poll() on the returned device handle but it always return POLLERR in the revents. I tried different parameters with timeout but it does not help. Here is the complete code.
/*
* libwebcam.h
*
* Created on: 13.04.2016
* Author: max
*/
#ifndef LIBWEBCAM_H_
#define LIBWEBCAM_H_
#include <stdint.h>
struct webcam
{
int fd;
uint32_t width;
uint32_t height;
uint32_t sizeimage;
uint32_t bytesperline;
uint8_t *image_buffer;
void *priv_data;
};
int webcam_open(struct webcam *w);
int webcam_close(struct webcam *w);
int webcam_take_image(struct webcam *w);
int webcam_poll(struct webcam *w);
#endif /* LIBWEBCAM_H_ */
/*
* libwebcam.c
*
* Created on: 13.04.2016
* Author: max
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <libv4l2.h>
#include <poll.h>
#include "libwebcam.h"
int webcam_open(struct webcam *w)
{
struct v4l2_capability caps;
struct v4l2_format fmt;
int dev_index;
int dev;
char buffer[255];
for (dev_index = 0; dev_index < 64; dev_index++) {
memset(&buffer, 0, sizeof(buffer));
sprintf(buffer, "/dev/video%d", dev_index);
#ifdef DEBUG
printf("libwebcam: Probing %s\n", buffer);
#endif
dev = v4l2_open(buffer, O_RDWR | O_NONBLOCK, 0);
if (dev != -1) {
memset(&caps, 0, sizeof(caps));
if (v4l2_ioctl(dev, VIDIOC_QUERYCAP, &caps) == -1) {
return -1;
}
if (caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
#ifdef DEBUG
printf("libwebcam: %s is video capture device\n", buffer);
#endif
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(v4l2_ioctl(dev, VIDIOC_G_FMT, &fmt) == -1) {
return -1;
}
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
if(v4l2_ioctl(dev, VIDIOC_S_FMT, &fmt) == -1) {
return -1;
}
if(v4l2_ioctl(dev, VIDIOC_G_FMT, &fmt) == -1) {
return -1;
}
if(w)
{
w->fd = dev;
w->bytesperline = fmt.fmt.pix.bytesperline;
w->height = fmt.fmt.pix.height;
w->sizeimage = fmt.fmt.pix.sizeimage;
w->width = fmt.fmt.pix.width;
w->image_buffer = calloc(fmt.fmt.pix.sizeimage, sizeof(uint8_t));
if(w->image_buffer == NULL)
return -1;
w->priv_data = calloc(1, sizeof(struct pollfd));
if(w->priv_data == NULL)
return -1;
return 0;
}
else
{
errno = EINVAL;
return -1;
}
}
}
}
errno = ENODEV;
return -1;
}
int webcam_close(struct webcam *w)
{
if(w)
{
if(w->image_buffer != NULL){
free(w->image_buffer);
w->image_buffer = NULL;
}
if(w->priv_data != NULL) {
free(w->priv_data);
w->priv_data = NULL;
}
if(w->fd != -1)
if(v4l2_close(w->fd) == -1)
return -1;
return 0;
}
errno = EINVAL;
return -1;
}
int webcam_take_image(struct webcam *w)
{
if(w)
{
return v4l2_read(w->fd, w->image_buffer, w->sizeimage * sizeof(uint8_t));
}
errno = EINVAL;
return -1;
}
int webcam_poll(struct webcam *w)
{
if(w)
{
((struct pollfd *)w->priv_data)->events = POLLIN;
((struct pollfd *)w->priv_data)->revents = 0;
((struct pollfd *)w->priv_data)->fd = w->fd;
if(poll(((struct pollfd*)w->priv_data), 1, -1) == -1)
{
return -1;
}
if(((struct pollfd*)w->priv_data)->revents & POLLIN) {
#ifdef DEBUG
printf("libwebcam: Data is available...\n");
#endif
return 1;
}
if(((struct pollfd*)w->priv_data)->revents & POLLERR) {
#ifdef DEBUG
printf("libwebcam: Error in poll...\n");
#endif
return -1;
}
#ifdef DEBUG
printf("libwebcam: Timeout...\n");
#endif
return 0;
}
#ifdef DEBUG
printf("libwebcam: Struct not valid...\n");
#endif
errno = EINVAL;
return -1;
}
/*
* test.c
*
* Created on: 14.04.2016
* Author: max
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libwebcam.h>
int main(int argc, char **argv)
{
struct webcam w;
int polled;
memset(&w, 0, sizeof(w));
if(webcam_open(&w) == -1)
{
perror("Unable to find webcam");
return EXIT_FAILURE;
}
while(1)
{
polled = webcam_poll(&w);
if(polled == -1)
{
perror("Error in poll");
return EXIT_FAILURE;
}
if(polled == 1)
{
webcam_take_image(&w);
}
}
if(webcam_close(&w) == -1)
{
perror("Unable to close webcam");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Can anyone tell me what is going on in the code?
I tested your code, and on my system the poll call is returning 0. From the man page, "A value of 0 indicates that the call timed out and no file descriptors were ready." So you should test for 0 in addition to -1 and 1.
I don't know why it fills in revents with POLLERR, but I would only check the resulting revents field if poll returned 1.
Also, not all V4L2 devices support read(), so you should check that your device supports it by testingcaps.capabilities & V4L2_CAP_READWRITE. My laptop webcam where I tested this does not support read/write.
See this example program for reference.

Resources