I have my PAM module:
I try to compile it, using string:
gcc -fPIC -DPIC -shared -rdynamic -o pam_test.so pam_test.c
But I have errors:
pam_test.c: In function ‘pam_sm_authenticate’:
pam_test.c:74:9: warning: passing argument 1 of ‘snprintf’ discards ‘const’ qualifier from pointer target type [enabled by default]
snprintf(msg[0].msg,60,"Second Password:%d:%d:%d:%d:",x1,x2,x3,x4);
^
In file included from pam_test.c:10:0:
/usr/include/stdio.h:386:12: note: expected ‘char * __restrict__’ but argument is of type ‘const char *’
extern int snprintf (char *__restrict __s, size_t __maxlen,
module code:
#include <security/pam_modules.h>
#include <stdarg.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#define PAM_SM_AUTH
#define MAX_V 30
PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv)
{
unsigned int ctrl;
int retval;
const char *name, *p;
char *right;
int x1,x2,x3,x4,y;
time_t mytime;
struct tm *mytm;
mytime=time(0);
mytm=localtime(&mytime);
srandom(mytime);
x1=random()%MAX_V;
x2=random()%MAX_V;
x3=random()%MAX_V;
x4=random()%MAX_V;
retval = pam_get_user(pamh, &name, "login: ");
{
struct pam_conv *conv;
struct pam_message *pmsg[3],msg[3];
struct pam_response *response;
retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
pmsg[0] = &msg[0];
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
msg[0].msg=malloc(100);
snprintf(msg[0].msg,60,"Second Password:%d:%d:%d:%d:",x1,x2,x3,x4);
retval = conv->conv(1, ( const struct pam_message ** ) pmsg
, &response, conv->appdata_ptr);
y=2*x1*mytm->tm_mday+x3*mytm->tm_hour;
right=malloc(100);
snprintf(right,20,"%d",y);
if (!(strcmp(right,response->resp))){
return PAM_SUCCESS;
}else{
return PAM_AUTH_ERR;
}
}
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags
,int argc, const char **argv)
{
unsigned int ctrl;
int retval;
retval = PAM_SUCCESS;
}
#ifdef PAM_STATIC
struct pam_module _pam_unix_auth_modstruct = {
"pam_test",
pam_sm_authenticate,
pam_sm_setcred,
NULL,
NULL,
NULL,
NULL,
};
#endif
The problem here is that in struct pam_message, the msg field is declared as const char*; that is, a pointer to an immutable string. So you're not supposed to overwrite it with snprintf.
A simple workaround is to write the string before inserting a pointer to it into msg:
char *s = malloc(100);
snprintf(s, 100, "Second Password:%d:%d:%d:%d:",x1,x2,x3,x4);
msg[0].msg = s;
Note: You should check the return value of snprintf. If the value returned is more than 100, then the string was truncated.
Related
my code: https://godbolt.org/z/de7fbdjh7
code from source: https://stackoverflow.com/a/49072888/15603477
Almost exact the same.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int iValue;
int kValue;
char label[6];
} my_data;
int cmp_mydata_ivalue(my_data* item1 , my_data* item2 )
{
if(item1->iValue < item2->iValue) return -1;
if(item1->iValue > item2->iValue) return 1;
return 0;
}
int main(void){
my_data datalist[256] = {0};
{
int i;
for(i = 0;i<20;i++){
datalist[i].iValue = i+100;
datalist[i].kValue = i+1000;
sprintf(datalist[i].label,"%2.2d", i+10);
}
}
printf("new line\n");
{
my_data srchitem = {105,1018,"13"};
my_data *foundItem = (my_data*) bsearch(&srchitem, datalist,20, sizeof(my_data),cmp_mydata_ivalue);
bsearch_results(&srchitem, foundItem);
}
}
The same question asked many times. But I don't know how to cast it.
error code:
*callback1.c: In function ‘main’:
callback1.c:58:89: warning: passing argument 5 of ‘bsearch’ from incompatible pointer type [-Wincompatible-pointer-types]
58 | my_data *foundItem = (my_data*) bsearch(&srchitem, datalist,20, sizeof(my_data),cmp_mydata_ivalue);
| ^~~~~~~~~~~~~~~~~
| |
| int (*)(my_data *, my_data *) {aka int (*)(struct <anonymous> *, struct <anonymous> *)}*
One way to try to use gcc option to supress the error. Another way is somewhere I need to cast. But now i don't know how to cast.
Tutorial I found so far: https://www.tutorialspoint.com/c_standard_library/c_function_bsearch.htm
The comparison function must have the type
int ( const void *, const void * )
See the declaration of the function bsearch
void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
So you should declare and define your function like
int cmp_mydata_ivalue( const void *a , const void *b )
{
const my_data *item1 = a;
const my_data *item2 = b;
if ( item1->iValue < item2->iValue) return -1;
if(item1->iValue > item2->iValue) return 1;
return 0;
}
Don't ever use workarounds to suppress errors/warnings from the compiler. You should carefully understand them and fix the code instead. If you chose to ignore them, you must be very conscious of what are the implications.
Having said that, the bsearch prototype is the following:
void* bsearch( const void *key, const void *ptr, size_t count, size_t size,
int (*comp)(const void*, const void*) );
meaning it expects the last parameter to be a function pointer to a function with the following signature:
int function(const void*, const void*);
What you are passing is a function of this kind
int cmp_mydata_ivalue(my_data* item1 , my_data* item2 )
Which is uncompatible, as C can't do any implicit cast. You must rewrite your function to something like this:
int cmp_mydata_ivalue( const void *cvp_item1 , const void *cvp_item2 )
{
const my_data *item1 = (const my_data *)cvp_item1;
const my_data *item2 = (const my_data *)cvp_item2;
}
I'm running a small rpc program/ using an rpc framework that takes a char[] from the client file and sends it to the server that enumerates the integers in the string.
I have a file client.c that takes user input and passes it to an external function in a header file.
#include <rpc/rpc.h>
#include "getNumInt.h"
int main(int argc, char **argv){
CLIENT *cli;
char *server;
server = argv[1];
cli = clnt_create(server, GETNUMINT, GNUMINT, "tcp"); //creates a client handle
/*does some check for whether the client connected*/
char command[256];
int *numInt;
fgets(command, 256, stdin);
numInt = enumints_1(&command, cli); //segfaults here according to backtrace
return(0);
}
The function enumints_1 is defined in my server stub server.c as:
int *enumints_1(msg, req)
char **msg; struct svc_req *req;{
printf(*msg);
static int numDigits = 0;
char msgcopy[256];
strcpy(msgcopy, *msg);
int i = 0;
for(i; i<strlen(msgcopy); i++){
if(msgcopy[i] >= '0' && msgcopy[i] <='9'){
numDigits++;
}
}
return(&numDigits);
}
My main issue is how I iterate through the char **msg as that is likely why my program is segfaulting.
command is just a string taken from user input and then passed by reference to the enumints_1 function.
Since it is a pointer to a point I assumed that I could just strcpy or memcpy to copy the string to a char array, but that doesn't work.
also my .x file:
struct intStringPair{
int numInts;
char msg[256];
};
program GETNUMINT{
version GNUMINT{
int ENUMINTS(string) = 1; //string considered char * the rpc generated file makes it so enumints_1 then has to take char **
int WRITEMESSAGE(intStringPair) = 2;
} = 1;
}= 0x20000001;
Like #user3386109 said:
command is not a pointer. So &command is not a pointer-to-a-pointer
so assigning &command to msg is not valid (and my compiler doesn't even compile it)
When I compile this code:
// my set up code
#include <stdio.h>
#include <string.h>
struct svc_req {};
typedef struct svc_req CLIENT;
struct svc_req *clnt_create(const char *, int, int, const char*) {return 0;}
int GETNUMINT=0, GNUMINT=0;
// your code verbatim
int *enumints_1(char **msg, struct svc_req *req){
printf(*msg);
static int numDigits = 0;
char msgcopy[256];
strcpy(msgcopy, *msg);
int i = 0;
for(i; i<strlen(msgcopy); i++){
if(msgcopy[i] >= '0' && msgcopy[i] <='9'){
numDigits++;
}
}
return(&numDigits);
}
int main(int argc, char **argv){
CLIENT *cli;
char *server;
server = argv[1];
cli = clnt_create(server, GETNUMINT, GNUMINT, "tcp"); //creates a client handle
/*does some check for whether the client connected*/
char command[256];
int *numInt;
fgets(command, 256, stdin);
numInt = enumints_1(&command, cli); //segfaults here according to backtrace
return(0);
}
The compiler says:
<source>: In function 'int main(int, char**)':
<source>:34:25: error: cannot convert 'char (*)[256]' to 'char**'
numInt = enumints_1(&command, cli); //segfaults here according to backtrace
^~~~~~~~
<source>:10:24: note: initializing argument 1 of 'int* enumints_1(char**, svc_req*)'
int *enumints_1(char **msg, struct svc_req *req){
~~~~~~~^~~
Compiler returned: 1
What you can do instead is make a pointer to the array and then pass the address of that:
// my set up code
#include <stdio.h>
#include <string.h>
struct svc_req {};
typedef struct svc_req CLIENT;
struct svc_req *clnt_create(const char *, int, int, const char*) {return 0;}
int GETNUMINT=0, GNUMINT=0;
// your code verbatim
int *enumints_1(char **msg, struct svc_req *req){
printf(*msg);
static int numDigits = 0;
char msgcopy[256];
strcpy(msgcopy, *msg);
int i = 0;
for(i; i<strlen(msgcopy); i++){
if(msgcopy[i] >= '0' && msgcopy[i] <='9'){
numDigits++;
}
}
return(&numDigits);
}
int main(int argc, char **argv){
CLIENT *cli;
char *server;
server = argv[1];
cli = clnt_create(server, GETNUMINT, GNUMINT, "tcp"); //creates a client handle
/*does some check for whether the client connected*/
char command[256], *command_pointer=command;
int *numInt;
fgets(command, 256, stdin);
numInt = enumints_1(&command_pointer, cli); //segfaults here according to backtrace
return(0);
}
I am using g_strsplit to split the msg with \n delimiter and created a function to break the string. The function breaks the msg and return to calling function thus I am not able to free the splitted string pointer in the called function. Thus tried to pass by reference the gchar. However I am getting segmentation fault.
#include <stdio.h>
#include <string.h>
#include <glib.h>
int split_message_syslog_forwarder(char **msg_full,gchar **splitted_strings)
{
int msg_length = -1;
*splitted_strings = g_strsplit(*msg_full, "\n", 2);
if (*splitted_strings != NULL)
{
sscanf(*splitted_strings[0], "%d", &msg_length);
if(msg_length<0)
{
*msg_full = *splitted_strings[1];
}
}
return msg_length;
}
int main()
{
int msg_length = -1;
char *msg_full = "12\nwhat is this";
gchar **splitted_strings;
int ret = split_message_syslog_forwarder(&msg_full,&splitted_strings);
printf("spilitted msg = %d",ret);
printf("spilitted msg 2= %s",msg_full);
return 0;
}
How can I pass the reference of gchar **splitted_string in glib?
int split_message_syslog_forwarder(char **msg_full,gchar **splitted_strings)
must be changed to
int split_message_syslog_forwarder(char **msg_full,gchar ***splitted_strings)
Compiler warns about this with -Wall:
xyz.c:5:5: note: expected 'gchar ** {aka char **}' but argument is of type 'gchar *** {aka char ***}'
int split_message_syslog_forwarder(char **msg_full,gchar **splitted_strings)
Compiling an XS-module including libmba I cannot solve this warning with my beginners level experience in C:
helmut#Helmuts-MacBook-Air:~/github/LCS-XS$ make
"/Users/helmut/perl5/perlbrew/perls/perl-5.18.2/bin/perl" "/Users/helmut/perl5/perlbrew/perls/perl-5.18.2/lib/5.18.2/ExtUtils/xsubpp" -typemap "/Users/helmut/perl5/perlbrew/perls/perl- 5.18.2/lib/5.18.2/ExtUtils/typemap" XS.xs > XS.xsc && mv XS.xsc XS.c
cc -c -I. -fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe - fstack-protector -I/usr/local/include -I/opt/local/include -O3 - DVERSION=\"0.01\" -DXS_VERSION=\"0.01\" "- I/Users/helmut/perl5/perlbrew/perls/perl-5.18.2/lib/5.18.2/darwin- 2level/CORE" XS.c
XS.xs:55:26: warning: passing 'const void *' to parameter of type 'AV *' (aka 'struct av *') discards qualifiers
[-Wincompatible-pointer-types-discards-qualifiers]
SV *line = *av_fetch(a, idx, 0);
^
/Users/helmut/perl5/perlbrew/perls/perl-5.18.2/lib/5.18.2/darwin- 2level/CORE/embed.h:51:46: note: expanded from macro
'av_fetch'
#define av_fetch(a,b,c) Perl_av_fetch(aTHX_ a,b,c)
^
/Users/helmut/perl5/perlbrew/perls/perl-5.18.2/lib/5.18.2/darwin- 2level/CORE/proto.h:178:44: note: passing argument to
parameter 'av' here
PERL_CALLCONV SV** Perl_av_fetch(pTHX_ AV *av, I32 key, I32 lval)
^
1 warning generated.
The compiled module is working fine. But is there a way to code it without warning?
The relevant parts in LCS/XS.xs:
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#include <string.h>
#include <mba/diff.h>
#include <mba/diff.c>
/* snipped */
inline
static const void *
_av_idx(const void *a, int idx, void *context)
{
//AV *av = a;
SV *line = *av_fetch(a, idx, 0);
STRLEN klen;
char *key = SvPVbyte(line, klen);
//printf("key: %s\n",key);
return key;
}
/* snipped */
void lcs_LCS(obj, s1, s2)
SV *obj
AV * s1
AV * s2
PREINIT:
struct CTX *ctx = (struct CTX *)SvIVX(SvRV(obj));
PPCODE:
int d, sn, i;
struct varray *ses = varray_new(sizeof(struct diff_edit), NULL);
IV n;
IV m;
n = av_top_index(s1);
m = av_top_index(s2);
// call libmba::diff()
d = diff(s1, 0, n, s2, 0, m, &_av_idx, &_cmp_str, NULL, 0, ses, &sn, NULL);
The part of mba/diff.h
typedef const void *(*idx_fn)(const void *s, int idx, void *context);
And in mba/diff.c:
int
diff(const void *a, int aoff, int n,
const void *b, int boff, int m,
idx_fn idx, cmp_fn cmp, void *context, int dmax,
struct varray *ses, int *sn,
struct varray *buf)
{
Is there a good practice to solve this warning without changing the source of libmba?
SOLVED:
inline
static const void *
_av_idx(const void *a, int idx, void *context)
{
SV *line = *av_fetch((AV *)a, idx, 0);
// ^^^^^^
STRLEN klen;
char *key = SvPVbyte(line, klen);
return key;
}
Well ... in _av_idx you are promising you will not change the contents of the first parameter
inline static const void *_av_idx(const void *a, int idx, void *context)
// ^^^^^
But then you proceed to send that parameter to a function (av_fetch(a, idx, 0)) that does not promise to not change it. That makes your promise a little strange.
Just remove your promise ...
inline static const void *_av_idx(void *a, int idx, void *context)
// no const ^^^^^^^
Edit
Or you could copy the argument to a local variable and pass that
inline
static const void *
_av_idx(const void *a, int idx, void *context)
{
AV *a_copy;
deep_copy(a_copy, a);
if (a_copy != NULL) {
SV *line = *av_fetch(a_copy, idx, 0);
free(a_copy);
} else {
/* error */
}
STRLEN klen;
char *key = SvPVbyte(line, klen);
//printf("key: %s\n",key);
return key;
}
What's wrong with this header? Gcc throws out:
libmmbox.h:7:29: error: expected ‘)’ before ‘*’ token
libmmbox.h:8:27: error: expected ‘)’ before ‘*’ token
Here's my code:
#ifndef __LIBMMBOX_H__
#define __LIBMMBOX_H__
int mmbox_connect(char *username);
int mmbox_login(int token, char *password);
int mmbox_quit();
int mmbox_stat(mmbox_stat_t *result);
int mmbox_list(mmbox_mail **l, int *num_msg);
int mmbox_send(char *dest, char *obj, void *buf, size_t size);
int mmbox_rcv(int id, void *buf, size_t size);
int mmbox_delete(int id);
int mmbox_resume(int id);
typedef struct
{
char *user;
int used_space;
int free_space;
int num_msg;
} mmbox_stat_t;
typedef struct
{
char *sender, *recipient; /
char *obj, *date;
char flags;
size_t size;
} mmbox_mail;
#endif
mmbox_stat_t struct is declared after it is used into a function signature. So the compiler doesn't still know this type when you declare:
int mmbox_stat(mmbox_stat_t *result);
Put your function prototypes after data structures definition.