I have asked this on the HDF Forum here but haven't received an answer (yet). So I thought I try my luck here.
I have created a small test file in Python (h5py) and want to use the H5LTget_attribute_string function to read an attribute from it. However, I'm not sure how to use this function.
My test file looks like this.
HDF5 "attr.h5" {
GROUP "/" {
DATASET "my_dataset" {
DATATYPE H5T_STD_I64LE
DATASPACE SIMPLE { ( 12 ) / ( 12 ) }
DATA {
(0): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
}
ATTRIBUTE "string_attr" {
DATATYPE H5T_STRING {
STRSIZE H5T_VARIABLE;
STRPAD H5T_STR_NULLTERM;
CSET H5T_CSET_UTF8;
CTYPE H5T_C_S1;
}
DATASPACE SCALAR
DATA {
(0): "this is a string"
}
}
}
}
}
Looking at the documentation of H5LT_GET_ATTRIBUTE it seems to me that I need to allocate a buffer and pass the address of the buffer as the last parameter, after which the H5LT_GET_ATTRIBUTE function would fill the buffer. My first attempt was therefore this.
#include <assert.h>
#include <stdlib.h>
#include "hdf5.h"
#include "hdf5_hl.h"
int main()
{
herr_t status;
hid_t file_id = H5Fopen("attr.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
assert(file_id >= 0);
char string[1024]; // assume buffer is large enough;
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
fprintf(stderr, "---- reading attribute ----\n");
status = H5LTget_attribute_string(file_id, "my_dataset",
"string_attr", string);
assert(status >= 0);
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
status = H5Fclose(file_id);
assert(status >= 0);
}
However this didn't work as expected, see the output below.
string :
pointer: 0x7ffe3f7ec770
---- reading attribute ----
string : #B�k2V
pointer: 0x7ffe3f7ec770
After some googling and experimenting I found out that the last parameter should be the address of the buffer. Then the H5LT_GET_ATTRIBUTE function will make the buffer point to the actual attribute value. The following function compiled with a warning but it gave the correct output.
#include <assert.h>
#include <stdlib.h>
#include "hdf5.h"
#include "hdf5_hl.h"
int main()
{
herr_t status;
hid_t file_id = H5Fopen("attr.h5", H5F_ACC_RDONLY, H5P_DEFAULT);
assert(file_id >= 0);
char* string = NULL;
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
fprintf(stderr, "---- reading attribute ----\n");
status = H5LTget_attribute_string(file_id, "my_dataset",
"string_attr", &string);
assert(status >= 0);
fprintf(stderr, "string : %s\n", string);
fprintf(stderr, "pointer: %p\n", string);
status = H5Fclose(file_id);
assert(status >= 0);
}
Output
string : (null)
pointer: (nil)
---- reading attribute ----
string : this is a string
pointer: 0x559e9e3d1240
Now I am perfectly happy to use it like this, and I can cast to **char to get rid of the warning, but I would like to be sure that this is the expected behavior. Ideally the documentation should be updated.
So my questions are:
Is the second example correct?
How long is the data in the string buffer valid? That is, when is the memory released by the HDF lib? (E.g. when the file is closed)
Should I use strcpy to copy the string data before using it?
As pointed by Scot Breitenfeld (from the HDF group):
If you are reading a variable length string with H5LTget_attribute_string (H5T_VARIABLE) then you don’t need to allocate the string, just pass in a pointer and the library will handle the allocations. If you are reading a fixed length string then you need to allocate a string that is “large enough”.
So, (1) your second approach seems ok to me.
As for (2) and (3), I would bet you are responsible for freeing the buffer, so no need to copy it. However, to be sure, you can use a debugger to check if the library is accessing the buffer or, even better, use valgrind to find memory leaks (when you try not to free the buffer).
I don't do HDF5, but I do enough C to provide you some answers with a very high percentage of being what you look for.
Is the second example correct?
yes it is. first because it returns the right and expected result, second
because any library that will fill a string (aka: char *) will need you to provide the address of a pointer (aka: char **).
How long is the data in the string buffer valid?
It is valid for as long as your program runs. This memory has been allocated for you with the right size, so it is valid for the entire lifetime of your program but it is now your responsibility to free it.
If you need more details on that please respond/comment to that message saying so and we'll help you.
Should I use strcpy to copy the string data before using it?
No you don't the memory has been alocated for you, you can keep it as is :-)
Next step that I advise you to do:
Now that you found the issue in their doc you should contact them and tell them.
Related
I am learning about file descriptors by using the open, write and close functions. What I expect is a printf statement outputting the file descriptor after the open function, and another printf statement outputting a confirmation of the text being written. However, I get the following result:
.\File.exe "this is a test"
[DEBUG] buffer # 0x00b815c8: 'this is a test'
[DEBUG] datafile # 0x00b81638: 'C:\Users\____\Documents\Notes'
With a blank space where the further debugging output should be. The code block for the section is:
strcpy(buffer, argv[1]); //copy first vector into the buffer
printf("[DEBUG] buffer \t # 0x%08x: \'%s\'\n", buffer, buffer); //debug buffer
printf("[DEBUG] datafile # 0x%08x: \'%s\'\n", datafile, datafile); //debug datafile
strncat(buffer, "\n", 1); //adds a newline
fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR); //opens file
if(fd == -1)
{
fatal("in main() while opening file");
}
printf("[DEBUG] file descriptor is %d\n", fd);
if(write(fd, buffer, strlen(buffer)) == -1) //wrting data
{
fatal("in main() while writing buffer to file");
}
if(close(fd) == -1) //closing file
{
fatal("in main() while closing file");
}
printf("Note has been saved.");
I basically copied the code word for word from the book I'm studying, so how could it not work?
The problem is that the printf function does not display anything, and the file descriptor is not returned.
Here is the full code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
void usage(char *pnt, char *opnt) //usage function
{
printf("Usage: %s <data to add to \"%s\">", pnt, opnt);
exit(0);
}
void fatal(char*); //fatal function for errors
void *ec_malloc(unsigned int); //wrapper for malloc error checking
int main(int argc, char *argv[]) //initiates argumemt vector/count variables
{
int fd; //file descriptor
char *buffer, *datafile;
buffer = (char*) ec_malloc(100); //buffer given 100 bytes of ec memory
datafile = (char*) ec_malloc(20); //datafile given 20 bytes of ec memory
strcpy(datafile, "C:\\Users\\____\\Documents\\Notes");
if(argc < 2) //if argument count is less than 2 i.e. no arguments provided
{
usage(argv[0], datafile); //print usage message from usage function
}
strcpy(buffer, argv[1]); //copy first vector into the buffer
printf("[DEBUG] buffer \t # %p: \'%s\'\n", buffer, buffer); //debug buffer
printf("[DEBUG] datafile # %p: \'%s\'\n", datafile, datafile); //debug datafile
strncat(buffer, "\n", 1); //adds a newline
fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR); //opens file
if(fd == -1)
{
fatal("in main() while opening file");
}
printf("[DEBUG] file descriptor is %d\n", fd);
if(write(fd, buffer, strlen(buffer)) == -1) //wrting data
{
fatal("in main() while writing buffer to file");
}
if(close(fd) == -1) //closing file
{
fatal("in main() while closing file");
}
printf("Note has been saved.");
free(buffer);
free(datafile);
}
void fatal(char *message)
{
char error_message[100];
strcpy(error_message, "[!!] Fatal Error ");
strncat(error_message, message, 83);
perror(error_message);
exit(-1);
}
void *ec_malloc(unsigned int size)
{
void *ptr;
ptr = malloc(size);
if(ptr == NULL)
{
fatal("in ec_malloc() on memory allocation");
return ptr;
}
}
EDIT: the issue has been fixed. The reason for this bug was that the memory allocated within the ec_malloc function was not sufficient, which meant that the text could not be saved. I changed the byte value to 100 and the code now works.
I am not sure which compiler you are using, but the one I tried the code with (GCC) says:
main.c:34:5: warning: ‘strncat’ specified bound 1 equals source length [-Wstringop-overflow=]
34 | strncat(buffer, "\n", 1); //adds a newline
| ^~~~~~~~~~~~~~~~~~~~~~~~
In other words, the call to strncat in your code is highly suspicious. You are trying to append a single line-break character, which has a length of 1, which you pass as the third argument. But strncat expects the third parameter to be the remaining space in buffer, not the length of the string to append.
A correct call would look a bit like this:
size_t bufferLength = 100;
char* buffer = malloc(bufferLength);
strncat(buffer, "\n", (bufferLength - strlen(buffer) - strlen("\n") - 1));
In this case, however, you are saved, because strncat guarantees that the resulting buffer is NUL-terminated, meaning that it always writes one additional byte beyond the specified size.
All of this is complicated, and a common source of bugs. It's easier to simply use snprintf to build up the entire string at one go:
size_t bufferLength = 100;
char* buffer = malloc(bufferLength);
snprintf(buffer, bufferLength, "%s\n", argv[1]);
Another bug in your code is the ec_malloc function:
void *ec_malloc(unsigned int size)
{
void *ptr;
ptr = malloc(size);
if(ptr == NULL)
{
fatal("in ec_malloc() on memory allocation");
return ptr;
}
}
See if you can spot it: what happens if ptr is not NULL? Well, nothing! The function doesn't return a value in this case; execution just falls off the end.
If you're using GCC (and possibly other compilers) on x86, this code will appear to work fine, because the result of the malloc function will remain in the proper CPU register to serve as the result of the ec_malloc function. But the fact that it just happens to work by the magic of circumstance does not make it correct code. It is subject to stop working at any time, and it should be fixed. The function deserves a return value!
Unfortunately, the GCC compiler is unable to detect this mistake, but Clang does:
<source>:64:1: warning: non-void function does not return a value in all control paths [-Wreturn-type]
}
^
The major bug in your code is a buffer overrun. At the top, you allocate only 20 bytes for the datafile buffer:
datafile = (char*) ec_malloc(20); //datafile given 20 bytes of ec memory
which means it can only store 20 characters. However, you proceed to write in more than 20 characters:
strcpy(datafile, "C:\\Users\\____\\Documents\\Notes");
That string literal is 33 characters, not including the terminating NUL! You need a buffer with at least 50 characters of space to hold all of this. With a buffer that is too small, the strcpy function call creates a classic "buffer overrun" error, which is undefined behavior that manifests itself as corrupting your program's memory area and thus premature termination.
Again, when I tried compiling and running the code, GCC reported:
malloc(): corrupted top size
because it detected that you had overrun the dynamically-allocated memory (returned by malloc). It was able to do this because, under the hood, malloc stores sentinel information after the allocated memory block, and your overwriting of the allocated space had written over its sentinel information.
The whole code is a bit suspect; it was not written by someone who knows C very well, nor was it debugged or reviewed by anyone else.
There is no real need to use dynamic memory allocation here in order to allocate fixed-size buffers. If you're going to use dynamic memory allocation, then allocate the actual amount of space that you need. Otherwise, if you're allocating fixed-size buffers, then just allocate on the stack.
Don't bother with complex string-manipulation functions when you can get away with simply using snprintf.
And as a bonus tip: when debugging problems, try to reduce the code down as small as you can get it. None of the file I/O stuff was related to this problem, so when I was analyzing this code, I replaced that whole section with:
printf("[DEBUG] file descriptor is %d\n", 42);
Once the rest of the code is working, I can go back and add the real code back to that section, and then test it. (Which I didn't do, because I don't have a file system handy to test this.)
I have tried to read documentation on mmap but I am still having a hard time understanding how to use it.
I want to take an argument from the command line and then allocate it to an executable memory region. Then I want to be able to execute from that code.
This is what I have so far:
int main(int argc, char const *argv[]) {
if (argc != 2) {
printf("Correct input was not provided\n");
exit(1);
}
char assembly_code[sizeof argv[1]];
const char *in_value = argv[1];
int x = sscanf(in_value, "%02hhx", assembly_code);
if (x != 1) {
printf("sscanf failed, exited\n");
exit(1);
}
void * map;
size_t ac_size = sizeof(assembly_code) / sizeof(assembly_code[0]);
map = mmap(NULL, ac_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS, -1, 0);
if (map == MAP_FAILED) {
printf("Mapping failed\n");
exit(1);
}
((void (*)(void))map)();
return 0;
}
This is the output/error I am getting: Mapping failed
I don't know if I am using mmap correctly. And if I am I don't believe I am executing it correctly.
For example if this file is run with an argument e8200000004889c64831c048ffc04889c74831d2b2040f054831c0b83c0000004831ff0f05e806000000584883c008c3ebf84869210a it should return Hi! and then terminate. I don't really know how to get this output after the map or how to "call/execute" a mmap.
int x = sscanf(read, "%02hhx", assembly_code);
This only converts a single byte. I don't think there is a standard library function to convert a whole string of hex bytes; you'll have to call sscanf in a loop, incrementing pointers within the input buffer read and the output buffer assembly_code as appropriate.
In your mmap call, if you don't want to map a file, you should use the flag MAP_ANONYMOUS instead of MAP_SHARED. You should also check its return value (it returns MAP_FAILED on error) and report any error. Also, the return value is in principle of type void * instead of int * (though this should make no difference on common Unix systems).
The mmap call (after being fixed) will return a pointer to a block of memory filled with zeros. There is no reason for it to contain your assembly_code, so you'll have to copy it there, perhaps with memcpy. Or you could move your loop and parse the hex bytes directly into the region allocated with mmap.
Your ((void (*)(void))map)(); to transfer control to the mapped address appears to be correct, so once you have the block correctly mapped and populated, it should execute your machine code. I haven't tried to disassemble the hex string you provided to see if it actually would do what you are expecting, but hopefully it does.
Also, read is not a very good name for a variable, since there is also a standard library function by that name. Your code will work, since the local variable shadows the global object, but it would be clearer to choose another name.
Oh, and char assembly_code[sizeof argv[1]]; isn't right. Think carefully about what sizeof does and doesn't do.
I have a file such as the following:
1-3-5 2 1
2 3-4-1 2
4-1 2-41-2 3-4
I want to return the number of columns of this file. I am reading the file with mmap in C. I have been trying to do with strtok(), but failing, so far. This is just a testfile, my original file is in GB scale.
pmap = mmap(0,mystat.st_size,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
char *start = pmap;
char *token;
token = strtok(start, "\t");
while (token != NULL){
printf("%s \n",token);
token = strtok(NULL, "\t");
col_len++;
}
I have been trying something on these lines, but, obviously there is a logical error. I am getting the following output:
number of cols = 1
Although, the # of cols should be 3.
It'd be great if you guys can help with any idea on how to parse this kind of a file using mmap.
I am using mmap because of faster execution for a single pass over the file.
It is hard to provide a definitive answer without a definitive question; as written, the question does not contain complete code, does not show the precise input, and does not show the debugging output.
But it is possible to provide some suggestions based on the non-applicability of strtok to this problem.
(strtok modifies its first argument, so it is really not a good idea to use it with an mmaped resource. However, that is not directly relevant to the problem you are having.)
You should ensure that the columns in the file are really separated by tabs. It seems to me most likely that the file contains spaces, not tabs, which is why the program reports that the entire file contains one column. If this were the only problem, you could call strtok with the second argument " \t" rather than "\t". But remember that strtok combines successive delimiters into a single separator so if the file is tab-separated and there are empty fields, strtok will not report the empty fields.
Related to the phrase "entire file" above, you do not tell strtok to recognized a newline character as terminating a token. So the strtok loop will try to analyze the entire file, counting the last field of each line as part of the same token as the first field of the next line. That is surely not what you want.
However, strtok overwrites the column delimiter that it finds, so if you did fix the strtok calls to include \n as a delimiter character, you would no longer be able to tell where the lines ended. That is probably important to your code, and it is a key reason why strtok is not an appropriate tool in this case. The Gnu strtok manpage (man strtok, emphasis added) provides a warning about this very issue (in the BUGS section at the end):
Be cautious when using these functions. If you do use them, note that:
These functions modify their first argument.
These functions cannot be used on constant strings.
The identity of the delimiting byte is lost.
There is no guarantee that a file ends with a NUL character. In fact, the file is very unlikely to contain a NUL character, and it is undefined behaviour to reference bytes in the mmap'ed region which are not in the file, but in practice most OSs will mmap an integral number of pages, zero-filling the last page. So 4095 times out of 4096, you will not notice this problem, and the 4096th time when the file is precisely an integral number of pages, your program will crash and burn, along with whatever sensitive equipment it is controlling. This is another reason strtok should never be used on mmaped files.
My comment was actually not correct, as you use MAP_PRIVATE, you don't risk destroying your file. But still, if you modify the memory area, the touched pages are copied, and you probably don't want this overhead, otherwise you could just copy the file to RAM from the beginning. So I'd still say: don't use strtok() here.
A solution with an own loop based on the functions in <ctype.h> is quite simple, though. As I wanted to try it myself, see here a working program to demonstrate it (the relevant part is the countCols() function):
#define _POSIX_C_SOURCE 200112L
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int countCols(const char *line, size_t maxlen)
{
int cols = 0;
int incol = 0;
const char *c = line;
while (maxlen && (!isspace(*c) || isblank(*c)))
{
if (isblank(*c))
{
incol = 0;
}
else
{
if (!incol)
{
incol = 1;
++cols;
}
}
++c;
--maxlen;
}
return cols;
}
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s [file]\n", argv[0]);
return EXIT_FAILURE;
}
struct stat st;
if (stat(argv[1], &st) < 0)
{
fprintf(stderr, "Could not stat `%s': %s\n", argv[1],
strerror(errno));
return EXIT_FAILURE;
}
int dataFd = open(argv[1], O_RDONLY);
if (dataFd < 0)
{
fprintf(stderr, "Could not open `%s': %s\n", argv[1],
strerror(errno));
return EXIT_FAILURE;
}
char *data = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, dataFd, 0);
if (data == MAP_FAILED)
{
close(dataFd);
fprintf(stderr, "Could not mmap `%s': %s\n", argv[1],
strerror(errno));
return EXIT_FAILURE;
}
int cols = countCols(data, st.st_size);
printf("found %d columns.\n", cols);
munmap(data, st.st_size);
return EXIT_SUCCESS;
}
I have an exercise in which I need to find the start and end address of a buffer (buf2). I don't have permissions to edit the code.
Here is the code:
(the password for the level2 code is fsckmelogic)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc, const char **argv) {
if (argc < 2) { printf("Fail. More Args...\n"); return 1; }
else {
setresuid(geteuid(),geteuid(),geteuid());
char buf2[4096];
char buf[16];
const char password[]="XXXXXXXXXXX";
strncpy(buf, argv[1], sizeof(buf) - 1);
if (strcmp(buf,password) != 0) {
printf("Wrong.\n");
return 1;
}
else {
strcpy(buf2,argv[2]);
printf("%s",buf2);
return 0;
}
}
}
ok, so no changing code however I'm assuming you can compile the code. Also, going to approach this from a hacker point-of-view (given the web site) and only use tools and techniques that might be available to a hacker. Finally I am making the assumption that you are working with a Linux box. So, lets compile the code like thus,
gcc level2.c -o so_test
Now we want to find out some starting addresses....so lets use ltrace (I'm hope it is installed on the system) and we get:
ltrace ./so_test XXXXXXXXXXX ababaabaabab
__libc_start_main(0x4006f0, 3, 0x7fff291bddb8, 0x400800 <unfinished ...>
geteuid() = 1000
geteuid() = 1000
geteuid() = 1000
setresuid(1000, 1000, 1000, -1) = 0
strncpy(0x7fff291bdcb0, "XXXXXXXXXXX", 15) = 0x7fff291bdcb0
strcmp("XXXXXXXXXXX","XXXXXXXXXXX") = 0
strcpy(0x7fff291bcca0, "ababaabaabab") = 0x7fff291bcca0
printf("%s", "ababaabaabab") = 12
ok...so what?
remember that strncpy returns a pointer to the destination string, and from the code
we know that the destination is buf, thus it's starting address is 0x7fff291bdcb0 (on my machine, your number will be different).
the third argument to strncpy is the number of characters to copy, which in this case is 15. From the code, we can see that the third argument of strncpy is sizeof(buf) - 1 which means that sizeof(buf) returns 16. From this we can deduce that the ending address of buf is 0x7fff291bdcb1 + 0x10 or ox7fff291bdcc1
we can also learn that the starting address of buf2 is 0x7fff291bcca0 from the results of the strcpy function call.
We can learn that the string entered by the user was 12 characters long due to the return value from the printf function call.
So now what is left is to find out the ending point of buf2. We can start throwing input at it till it blows up on us. Hint, if you do not want to type a long string of the same character, you can do the following:
ltrace ./so_test XXXXXXXXXXX `perl -e "print 'A' x 1024;"`
just change the 1024 to how many characters you want to pump into buf2. On my system, through a bit of trial and error, I've found out that the largest value that I can input is 4151, pushing in 4152 A's result in a segmentation fault (so we know that the maximum size of buf2 is going to be less than this).
Only thing left do do is figure out the length of buf2.
Hopefully this give you a start, I don't want to do your entire challenge for you :)
If you cannot modify the code, and your assignment is to get the beginning and ending ADDRESS of buf2, then isn't the only thing left is to run it with a debugger, and obtain the address from there??
The Starting Address of Buffer can be viewed using
printf("%p", &buff2);
Once you get the starting point of address then find the length of the buffer i.e.
len=strlen(buff2);
Now add the length in pointer then you get he end address of buff2 i.e.
printf("%p %p", *buff2, *buff2+strlen(buff2));
I'm new to C, I got an error today which is:
segmentation fault core dumped
I used gdb to track the code, I found that the error occurs in this line:
if (!strcmp(user_pass, passwddata->passwd))
Where user_pass is a char array, and passwddata is a struct, passwd is a member of the struct, which is also a type of char array, I tried to change the code to
if (!strcmp(user_pass, "ttt"))
The error didn't occur, so I guess the error occurs on that struct, if more code is needed, I can add it, here I want to understand under what condition can such kind of error occur on a struct?
Here is the code:
int main(int argc, char *argv[]) {
mypwent *passwddata; /* this has to be redefined in step 2 */
/* see pwent.h */
char important[LENGTH] = "***IMPORTANT***";
char user[LENGTH];
//char *c_pass; //you might want to use this variable later...
char prompt[] = "password: ";
char *user_pass;
sighandler();
while (TRUE) {
/* check what important variable contains - do not remove, part of buffer overflow test */
printf("Value of variable 'important' before input of login name: %s\n",
important);
printf("login: ");
fflush(NULL); /* Flush all output buffers */
__fpurge(stdin); /* Purge any data in stdin buffer */
if (gets(user) == NULL) /* gets() is vulnerable to buffer */
{
exit(0); /* overflow attacks. */
}
printf("******************* %s\n",user);
/* check to see if important variable is intact after input of login name - do not remove */
printf("Value of variable 'important' after input of login name: %*.*s\n",
LENGTH - 1, LENGTH - 1, important);
user_pass = getpass(prompt);
passwddata = getpwnam(user);
printf("^^^^^^^^^^^^^^^^^^^^^^^^^^ %s\n", user_pass);
if (passwddata != NULL) {
/* You have to encrypt user_pass for this to work */
/* Don't forget to include the salt */
if (!strcmp(user_pass, "ttt")) {
printf(" You're in !\n");
/* check UID, see setuid(2) */
/* start a shell, use execve(2) */
}
}
printf("Login Incorrect \n");
}
return 0;
}
Most likely passwd or passwddata is NULL, in the latter case the -> is attempting to deference the NULL pointer and thus it's crashing.
By changing your code to:
if (!strcmp(user_pass, "ttt"))
You isolated the first part, so you know user_pass is OK. You can use a debugger or some checks and printf's to get the values of passwddata and passwd to close on what the problem is.
Now that you've updated the code you know the problem is with passwd. You start with an empty pointer:
mypwent *passwddata;
Later you set the pointer to the return of getpwnam, presumably this is a pointer to a structure of type mypwent that you allocated some memory for:
passwddata = getpwnam(user);
You have a check to make sure passwddata isn't null:
if (passwddata != NULL) {
if (!strcmp(user_pass, "ttt")) {
So now you've checked everything except passwd, passing a null into strcmp() will cause it to crash with that message, so I'm guessing you only allocated memory for the structure and not for the char array within the structure.
My guess would be that passwddata is NULL.
Or the buffer passwddata->passwd points to
shorter than the string in user_pass
and
not null-terminated
Together those two make strcmp access beyond the limits of the second argument's buffer and hence cause the error.