i want to capture following string in c with sscanf
"1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4"
but sscanf only fills &customInput.type and customInputTitle[0] with "Salam Khobi" and other part of string would not scan.
#include <stdio.h>
#include <stdlib.h>
typedef enum {
INPUT_NUMBER = 0,
INPUT_NORMAL = 1,
INPUT_PASSWORD = 2,
INPUT_PAYAMOUNT = 3,
} inputType;
typedef struct {
char * title[2];
char * extra[2];
inputType type;
unsigned minLen:6;
unsigned maxLen:6;
unsigned forceLen:1;
unsigned editable:1;
unsigned char data[100];
} lcdInput;
#define CUSTOM_INPUT_LENGTH 40
static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
static lcdInput customInput = {
.title = {&customInputTitle[0], &customInputTitle[1]},
.extra = {&customInputExtra[0], &customInputExtra[1]},
.type = INPUT_NORMAL,
.editable = 1,
.forceLen = 0,
};
int main()
{
memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
memset(&customInputExtra, 0, CUSTOM_INPUT_LENGTH << 1);
sscanf(payload, CUSTOM_INPUT_REGX,
&customInput.type,
&customInputTitle[0], &customInputTitle[1],
&customInputExtra[0], &customInputExtra[1]);
return 0;
}
"%d=%[^|]|%[^=]=%[^|]|%s" is the correct format.
The Problem Asked About
After a | character is encountered with the scanset directive %[^|], sscanf() will resume matching with the | character. The next directive should be a literal | to avoid a matching failure. In the original code, with %[^|]s, the s is not a part of the scanset directive, and instead sscanf() seeks to match a literal s in the input. Also, note that maximum width specifiers should always be used with the %s and %[] fscanf() family directives to avoid buffer overflow with malicious or malformed inputs:
"%d=%39[^|]|%39[^=]=%39[^|]|%39s"
Some Other Serious Issues
Always enable warnings when compiling C code; doing so here would have helped you avoid several serious problems. There are a lot of warnings for this code, and most of the problems listed below lead to undefined behavior. I always use at least gcc -std=c11 -Wall -Wextra -Wpedantic, and I have added a sample of gcc output for the original code at the end of the answer.
The posted code is missing #include <string.h> for memset().
The .title and .extra fields of lcdInput should be unsigned char *, since these point to the first elements of unsigned char arrays.
In the initialization of customInput the & operators should be removed. customInput.title and customInput.extra are both expecting pointers to unsigned char (or chars before the above correction). With, e.g. &customInputTitle[0] you have a pointer to an array of CUSTOM_INPUT_LENGTH unsigned chars (or chars before the above correction); this is a type mismatch, and your compiler should complain vociferously (with warnings enabled). Instead, just use:
static lcdInput customInput = {
.title = {customInputTitle[0], customInputTitle[1]},
.extra = {customInputExtra[0], customInputExtra[1]},
.type = INPUT_NORMAL,
.editable = 1,
.forceLen = 0,
};
Here, customInputTitle[0] is an array of CUSTOM_INPUT_LENGTH unsigned chars, which will decay to a pointer to its first element (unsigned char *). Alternatively, you could use &customInputTitle[0][0], &customInputTitle[1][0], etc.
Similarly, you need to remove the ampersands from the customInput arrays in the call to sscanf(). Here you also need to do something about &customInput.type. This is an enum type, and you can't input an enum value. Again, the compiler complains with warnings enabled. Instead, try:
int typeInput;
if (sscanf(payload, CUSTOM_INPUT_REGX,
&typeInput,
customInputTitle[0], customInputTitle[1],
customInputExtra[0], customInputExtra[1]) == 5) {
if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) {
customInput.type = typeInput;
} else {
/* Handle error */
}
};
Here typeInput is used to collect input, the value returned by sscanf() is checked to verify that the correct number of values was assigned, and the value of typeInput is checked against the value range for inputType. If input is as expected, typeInput is assigned to customInput.type.
The calls to memset() will work, but why obfuscate things with bitshifts? You don't need the & operators here, either, but in this case they are OK. Instead, consider:
memset(customInputTitle, 0, sizeof customInputTitle);
memset(customInputExtra, 0, sizeof customInputExtra);
Here is the corrected code. This compiles with no warnings using gcc -std=c11 -Wall -Wextra -Wpedantic:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // missing header
typedef enum {
INPUT_NUMBER = 0,
INPUT_NORMAL = 1,
INPUT_PASSWORD = 2,
INPUT_PAYAMOUNT = 3,
} inputType;
typedef struct {
unsigned char * title[2]; // need unsigned char
unsigned char * extra[2];
inputType type;
unsigned minLen:6;
unsigned maxLen:6;
unsigned forceLen:1;
unsigned editable:1;
unsigned char data[100];
} lcdInput;
#define CUSTOM_INPUT_LENGTH 40
static unsigned char customInputTitle[2][CUSTOM_INPUT_LENGTH];
static unsigned char customInputExtra[2][CUSTOM_INPUT_LENGTH];
const char * payload = "1=Salam Khobi|FC93F8A120F491F3A8=Rial|F191FEA4";
// bad format string
#define CUSTOM_INPUT_REGX "%d=%39[^|]|%39[^=]=%39[^|]|%39s"
// & operator not needed
static lcdInput customInput = {
.title = {customInputTitle[0], customInputTitle[1]},
.extra = {customInputExtra[0], customInputExtra[1]},
.type = INPUT_NORMAL,
.editable = 1,
.forceLen = 0,
};
int main(void)
{
// could use improvements
memset(customInputTitle, 0, sizeof customInputTitle);
memset(customInputExtra, 0, sizeof customInputExtra);
// & operators not needed
int typeInput;
if (sscanf(payload, CUSTOM_INPUT_REGX,
&typeInput,
customInputTitle[0], customInputTitle[1],
customInputExtra[0], customInputExtra[1]) == 5) {
if (typeInput >= INPUT_NUMBER && typeInput <= INPUT_PAYAMOUNT) {
customInput.type = typeInput;
} else {
/* Handle error */
}
};
return 0;
}
GCC Output with Warnings
Here are the compiler warnings with gcc -std=c11 -Wall -Wextra -Wpedantic from the original program posted in the question:
bad_program.c:27:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.title = {&customInputTitle[0], &customInputTitle[1]},
^
bad_program.c:27:19: note: (near initialization for ‘customInput.title[0]’)
bad_program.c:27:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.title = {&customInputTitle[0], &customInputTitle[1]},
^
bad_program.c:27:41: note: (near initialization for ‘customInput.title[1]’)
bad_program.c:28:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.extra = {&customInputExtra[0], &customInputExtra[1]},
^
bad_program.c:28:19: note: (near initialization for ‘customInput.extra[0]’)
bad_program.c:28:41: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
.extra = {&customInputExtra[0], &customInputExtra[1]},
^
bad_program.c:28:41: note: (near initialization for ‘customInput.extra[1]’)
bad_program.c: In function ‘main’:
bad_program.c:36:5: warning: implicit declaration of function ‘memset’ [-Wimplicit-function-declaration]
memset(&customInputTitle, 0, CUSTOM_INPUT_LENGTH << 1);
^~~~~~
bad_program.c:36:5: warning: incompatible implicit declaration of built-in function ‘memset’
bad_program.c:36:5: note: include ‘<string.h>’ or provide a declaration of ‘memset’
bad_program.c:25:33: warning: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘inputType * {aka enum <anonymous> *}’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 4 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^=’ expects argument of type ‘char *’, but argument 5 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%[^|’ expects argument of type ‘char *’, but argument 6 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
bad_program.c:25:33: warning: format ‘%s’ expects argument of type ‘char *’, but argument 7 has type ‘unsigned char (*)[40]’ [-Wformat=]
#define CUSTOM_INPUT_REGX "%d=%[^|]s|%[^=]s=%[^|]s|%s"
^
bad_program.c:39:21: note: in expansion of macro ‘CUSTOM_INPUT_REGX’
sscanf(payload, CUSTOM_INPUT_REGX,
^~~~~~~~~~~~~~~~~
After reading Structure and Interpretation of Computer Programs (SICP) I decided to find a way to implement some of these functional programming techniques using C. I tried to write a program that makes a pair whose first argument is a name of the function and second arg is any function that takes one arg and returns one arg. Using implementation below I was expecting to see
an output like:
fact(7) = 5040
fib(7) = 13
but instead I am getting
fact(7) = 5040
fib(7) = 0
along with warnings
$ cc map.c
map.c: In function ‘main’:
map.c:41:17: warning: assignment from incompatible pointer type [enabled by default]
maps[0].f_ptr = &fact;
^
map.c:43:17: warning: assignment from incompatible pointer type [enabled by default]
maps[1].f_ptr = &fib;
^
map.c:47:7: warning: passing argument 1 of ‘maps[i].f_ptr’ makes pointer from integer without a cast [enabled by default]
ans = (int) maps[i].f_ptr((int) num);
^
map.c:47:7: note: expected ‘void *’ but argument is of type ‘int’
map.c:47:13: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
ans = (int) maps[i].f_ptr((int) num);
^
map.c:52:7: warning: passing argument 1 of ‘maps[i].f_ptr’ makes pointer from integer without a cast [enabled by default]
ans2 = (int) maps[i].f_ptr((int) num);
^
map.c:52:7: note: expected ‘void *’ but argument is of type ‘int’
map.c:52:14: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
ans2 = (int) maps[i].f_ptr((int) num);
during compilation. Looking at the code I don't see the problem but then again I haven't used C in quite some time. Is there a better way to implement such a construct and why is fib(7) printing a 0 instead of 13?
Here's my code:
struct Map
{
char* name;
void* (*f_ptr)(void*);
};
int fact(int a) {
if (a == 0)
return 0;
if (a == 1)
return 1;
return a * fact (a-1);
}
int fib(int a) {
if (a == 0)
return 0;
if (a == 1)
return 1;
return fib(a-1) + fib(a-2);
}
int findFunc (char* str, struct Map map)
{
if (map.name == str)
return 1;
return 0;
}
int main()
{
int i = 0;
int ans = 0;
int ans2 = 0;
int num = 7;
struct Map maps[2];
maps[0].name = "fact";
maps[0].f_ptr = &fact;
maps[1].name = "fib";
maps[1].f_ptr = &fib;
for (i; i < (sizeof(maps)/sizeof(maps[0])); i++) {
if (findFunc("fact", maps[i]))
ans = (int) maps[i].f_ptr((int) num);
}
for (i; i < (sizeof(maps)/sizeof(maps[0])); i++) {
if (findFunc("fib", maps[i]))
ans2 = (int) maps[i].f_ptr((int) num);
}
printf("fact(%d) = %d\n", num, ans);
printf("fib(%d) = %d", num, ans2);
return 0;
}
String comparisons
This is not how you do string comparison in C.
if (map.name == str)
This is how you do string comparison in C.
if (0 == strcmp(map.name, str))
Because strings in C are just pointers to characters, map.name == str checks if map.name and str are identical pointers (point to the same block of memory), not whether what they point to is the same.
for loops
Your code is probably reporting fib(7) = 0 because it's failing to find fib. One possible culprit is the string comparison issue I mentioned. However, your for loop syntax is also odd:
for (i; i < (sizeof(maps)/sizeof(maps[0])); i++) {
You don't set i to anything, so this means, "Starting from wherever i happens to be, do the following..."
To loop over all of maps, use this:
for (i = 0; i < (sizeof(maps)/sizeof(maps[0])); i++) {
type warnings
As #alk said in a comment, the reason you're getting all of those warnings is because you've declared a function type of void* (*f_ptr)(void*);, even though your functions are int (*)(int). If you want to keep using void* to allow different types, and you're careful enough with your types to make this work, then you can add casts to silence the warnings.
maps[0].f_ptr = (void *(*)(void*)) &fact;
ans2 = (int) maps[i].f_ptr((void*) num);
Etc.
Better implementations?
A "real" implementation of mapping functions to names would use a hash table, instead of linearly searching for matching names. Implementing a hash table in C would add complexity and may not be worth it for this exercise.
but instead I am getting
[...]
fib(7) = 0
The code misses to initialise i to 0 for the 2nd for-loop.
I am using Mhash and I would like to print the length of my blocksize for debugging purposes, but I keep getting an error every time I try to compile
Any suggestions on how I can fix this error?
Here is my code:
#include <mhash.h>
#include <stdio.h>
#include <string.h>
// 0x12e6bc6e68c3b9506e6668db6b7224f894fab073728fc179 (TIGER192) (48)
int main()
{
char password[] = "Jefe";
int keylen = 4;
char data[] = "what do ya want for nothing?";
int datalen = 28;
MHASH td, td2;
unsigned char *mac, *mac2;
int i, j;
td = mhash_hmac_init(MHASH_TIGER192, password, keylen, mhash_get_hash_pblock(MHASH_TIGER192));
mhash(td, data, datalen);
mac = mhash_hmac_end(td);
printf("0x");
for (i = 0; i < mhash_get_block_size(MHASH_TIGER192); i++)
{
printf("%.2x", mac[i]);
}
printf("\n");
// int length = strlen(mac);
// printf(length);
// int length = 5;
// printf(length);
exit(0);
}
I run the program with the following commands:
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hb2#hb1:~/Desktop$ ./hashexample
0x12e6bc6e68c3b9506e6668db6b7224f894fab073728fc179
And it runs successfully, but when I try to print the length of the hashed result, I get the following error!!? Any ideas on why?
// int length = strlen(mac);
// printf(length);
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hashexample.c: In function ‘main’:
hashexample.c:33:2: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:363:12: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
hashexample.c:33:2: warning: format not a string literal and no format arguments [-Wformat-security]
At first, I thought it was because I thought I was using strlen incorrectly?! But even when I try to do a simple printf of an integer, I still get an error:
// int length = 5;
// printf(length);
hb2#hb1:~/Desktop$ gcc -o hashexample hashexample.c -lmhash
hashexample.c: In function ‘main’:
hashexample.c:35:2: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:363:12: note: expected ‘const char * __restrict__’ but argument is of type ‘int’
hashexample.c:35:2: warning: format not a string literal and no format arguments [-Wformat-security]
Thanks for your help in advance!
Check the man page for printf(). The first argument is a const char *. You're passing an int.
That's what the warning says too:
warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
You wanted:
printf("%d", length);
You need the format string to specify that an int is going to be printed.
I want to allocate memory for holding a field extracted from a given string. The size of the field is determined by the difference of two pointers, see the following minimal example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
const char line[] = "foo,bar,baz";
char *field_start = line;
char *field_end;
char *field;
field_end = strchr(line, ',');
field = malloc(field_end - field_start + 1);
memcpy(field, field_start, field_end - field_start);
*(field + (field_end - field_start)) = '\0';
printf("field=\"%s\"\n", field);
/* ... */
return (0);
}
Compiling this code with clang -Weverything -o ex ex.c results in the following warnings:
ex.c:14:41: warning: implicit conversion changes signedness: 'long' to 'unsigned long'
[-Wsign-conversion]
field = malloc(field_end - field_start + 1);
~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~^~~
ex.c:15:39: warning: implicit conversion changes signedness: 'long' to 'unsigned long'
[-Wsign-conversion]
memcpy(field, field_start, field_end - field_start);
~~~~~~ ~~~~~~~~~~^~~~~~~~~~~~~
As I understand it, the result of the pointer difference is of ptrdiff_t type while the malloc/memcpy expect an argument of type size_t.
So my question is how to address this and to eliminate the warning? As
field_end >= field_start the difference cannot become negative, so could the
above be safely casted to size_t
field = malloc(size_t(field_end - field_start + 1));
memcpy(field, size_t(field_start, field_end - field_start));
or are the any problems I'm overlooking?
Note:
There are no checks for return values in the above just for simplicity. field_start and _end should be const of course.
field_end >= field_start only holds in case strchr does not return NULL, i.e. nothing in the type system tells the compiler that this indeed always holds. Hence the warning is warranted. However, if you make sure that this is not the case, then (size_t)(field_end - field_start) should be fine. In order to not duplicate this all over, I'd add
size_t field_len;
/* memchr & null-check go here */
field_len = (size_t)(field_end - field_start);
...and then use field_len all over.
That being said, you may want to replace your malloc/memcpy combination with a call to strndup.
I need to decrypt wpa 2 psk programming in c. Assuming that i alredy have the TK (need to decrypt only unicast) I'm trying to decrypt packets whit the following code (with no luck actually):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/pem.h>
#include <openssl/bn.h>
#include <openssl/aes.h>
struct ctr_state {
unsigned char ivec[128];
unsigned int num;
unsigned char ecount[128];
};
void init_ctr(struct ctr_state *state, const unsigned char iv[16]){ //
state->num = 0;
memset(state->ecount, 0, 128);
memset(state->ivec, 0, 128);
memcpy(state->ivec, iv, 16);
}
char * extochar(char * in, int inLen){
int i,k;
int resInt[inLen/2];
char * resChar=malloc(inLen/2);
k=0;
for(i=0; i<inLen/2; i=i++){
resInt[k]=chartoint(in[i*2])<<4;
resInt[k]+=chartoint(in[(i*2)+1]);
k++;
}
for(k=0; k<inLen/2;k++){
resChar[k]=(char)resInt[k];
}
return resChar;
}
int chartoint(char car){
int intero = 0;
intero = car - '0';
if(intero < 10 && intero > -1)
return intero;
else
return car - 'a' + 10;
}
void main(){
unsigned char * po = extochar("00",2);
unsigned char * a2 = extochar("0012f0be7301",12);
unsigned char * pn = extochar("000000000052",12);
unsigned char * nonce= malloc(13);
char * hextk= "15b1657878b1d12c93b4e073e42b629a";
unsigned char * tk= extochar(hexstr, strlen(hextk));
init_ctr(&status, nonce);
nonce[0]=po[0];
nonce[1]=a2[0];
nonce[2]=a2[1];
nonce[3]=a2[2];
nonce[4]=a2[3];
nonce[5]=a2[4];
nonce[6]=a2[5];
nonce[7]=pn[0];
nonce[8]=pn[1];
nonce[9]=pn[2];
nonce[10]=pn[3];
nonce[11]=pn[4];
nonce[12]=pn[5];
AES_KEY aes_key;
if(AES_set_encrypt_key(tk, 128, &aes_key))
exit(-1);
//encrypted payload
char * ext_crypt = "146a056e3b20ece434594373a0e4fcbc83114c9a1bc158ecc4ca6bb449d6ec8468c8e08af3f4f33ce961f7b42c7651e22042e0bf39bd864a1b5f1035af5a54986183ee79446e3fb80a6f9bbb7a0177f557ce192c5515bd3a671b73464b9cf0fb817fd614987b65c0e20d753dedab8bf1934294e112cb865effb14724a2c66fcc7956f8fcfb0f7f2e539fbbf4e30c08fc18d10eb143510eae8b88e911c1cee773b73cdaf6d45151ad01fb2e2f5aa014510a";
int msg_len= strlen(ext_crypt)/2 - 12;
unsigned char * crypt = extochar(ext_crypt, strlen(ext_crypt));
AES_ctr128_encrypt(crypt, cleartxt, msg_len, &aes_key, status.ivec, status.ecount, &status.num);
}
The output should be something like that:
-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 2
ST: urn:schemas-upnp-org:service:WANPPPConnection:1
I pasted the source of the encrypted packet here: http://pastebin.com/RvkfSt54
are there any problems in the code or in the data, and how can I solve them?
thanks a lot!
Aside from the code being uncommented and somewhat poorly formatted... your question whether there are "any problems in the code" can be answered by your compiler, if you enable warnings (which you should always do):
test.c: In function ‘extochar’:
test.c:28:26: warning: operation on ‘i’ may be undefined
test.c:29:13: warning: implicit declaration of function ‘chartoint’
test.c: At top level:
test.c:40:5: error: conflicting types for ‘chartoint’
test.c:40:1: note: an argument type that has a default promotion can’t match an empty parameter name list declaration
test.c:29:23: note: previous implicit declaration of ‘chartoint’ was here
test.c:49:6: warning: return type of ‘main’ is not ‘int’
test.c: In function ‘main’:
test.c:51:26: warning: pointer targets in initialization differ in signedness
test.c:52:26: warning: pointer targets in initialization differ in signedness
test.c:53:26: warning: pointer targets in initialization differ in signedness
test.c:56:34: error: ‘hexstr’ undeclared (first use in this function)
test.c:56:34: note: each undeclared identifier is reported only once for each function it appears in
test.c:57:15: error: ‘status’ undeclared (first use in this function)
test.c:79:30: warning: pointer targets in initialization differ in signedness
test.c:80:31: error: ‘cleartxt’ undeclared (first use in this function)