pam_acct_mgmt seg faulting when Max Num of Days is < Num days of warning before expiration - c

I am writing a very simple PAM authentication function shown below.
int authenticate(char* user, char* pass)
{
int value = pam_start("passwd", user, &conv, &pamh);
if (value == PAM_SUCCESS)
{
reply = (struct pam_response*)malloc(sizeof(struct pam_response));
reply[0].resp = pass;
reply[0].resp_retcode = 0;
value = pam_authenticate(pamh, 0);
if (value == PAM_SUCCESS)
{
// This call is seg faulting.
value = pam_acct_mgmt(pamh, 0);
return value;
}
else
printf("Failed on Authentication\n");
}
}
pam_end(pamh, value);
return value;
}
conv is defined as the following:
int nullConv(int num_msg, const struct pam_message** msg, struct pam_response** resp,
void* appdata_ptr)
{
*resp = reply;
return PAM_SUCCESS;
}
static struct pam_conv conv = { nullConv, NULL };
This is a very simple function that works most of the time. I am working on a Linux box. When I mess with a user account, say bob and make his Maximum number of days between password change less than Number of days of warning before password expires by using...
#chage -M 28 bob
#chage -W 29 bob
The application seg faults at the call to pam_acct_mgmt. If I change it so that the Maximum number is greater than the Number before warning, my application runs as expected.
#chage -M 30 bob. Now I'm fine and the user can log in.

I found the following post:
https://serverfault.com/questions/249671/switch-on-pam-debugging-to-syslog
and followed the accepted solution. The results I found in my /var/log/debug.log file stated pam_tally(system-auth:auth): unknown option: reset
The line in my PAM /etc/pam.d/system-auth file it was referring to was a line that read
account required pam_tally.so reset
When I removed the reset option, everything works fine.
By the way pam_vsyslog has a serious bug. It was segfaulting on a simple strcmp.

Related

Re-arranging pointers in a struct doesn't give me the correct result

I have this struct
typedef struct InfoSession {
TabNodePtr FirstTab;
TabNodePtr LastTab;
TabNodePtr CurrTab;
TabNodePtr AuxTab;
char *OpeningAddress;
} InfoSession;
which has to be a browser session that controls all its tabs. The OpeningAddress is the default address when opening a new tab.
My main looks like this:
int main() {
InfoSessionPtr MySession1 = NULL, MySession2 = NULL, CurrSession = NULL;
int option, flag, n;
char *OpeningAddress == NULL;
...
}
When I want to change the OpeningAddress using this function:
void SessionNewOpeningAddress(InfoSessionPtr Session, char *OpeningAddress1) {
Session->OpeningAddress = OpeningAddress1;
}
everything works fine and the new opening address I add is displayed correctly. But, when I have two sessions at the same time, changing the OpeningAddress of the second session also changes the OpeningAddress of the first session (When adding a second session, after I've inserted a new OpeningAddress to the first session, the OpeningAddress of the second session isn't the same as the first session).
For example, if I change the opening address of the first session to "AA", adding a new session after that makes the OpeningAddress of the second session to be NULL, and not "AA" (Which is what I want).
Adding the new session(s):
if (MySession1 == NULL && MySession2 == NULL) {
MySession1 = SessionNew(OpeningAddress);
CurrSession = MySession1;
printf("\nNew Session (first) created!\n");
printf("First Session assigned as 'Current' Session\n");
} else {
MySession2 = SessionNew(OpeningAddress);
CurrSession = MySession2;
printf("\nA Session already exists, created a second one.\n");
printf("Second Session assigned as 'Current' Session\n");
}
Changing the opening address:
printf("\nInsert the new Opening Address:\n");
scanf("%s", OpeningAddress);
SessionNewOpeningAddress(CurrSession, OpeningAddress);
Also, the code changing which session to manage:
printf("\nPress 1 to manage first Session or 2 to manage second Session:\n");
scanf("%d", &n);
getchar();
if (n == 1){
CurrSession = MySession1;
printf("\nManaging first Session\n");
} else if (n == 2){
CurrSession = MySession2;
printf("\nManaging second Session\n");
}
Thanks for your help.
The problem is simple:
the call SessionNewOpeningAddress(CurrSession, OpeningAddress); sets the OpeningAddress member of the CurrSession to point to an array in the caller's scope that gets overwritten after this call. Indeed all OpeningAddress fields may point to the same array in the calling function.
posting code fragments as you did is not helpful, much of the context is missing and some other code might cause the problem.
hiding pointers behind typedefs as in TabNodePtr is highly discouraged. It leads to confusing code for beginners and advanced programmers alike.
To fix your problem, you could make a copy of the string:
#include <string.h>
void SessionNewOpeningAddress(InfoSessionPtr Session, char *OpeningAddress1) {
Session->OpeningAddress = OpeningAddress1 ? strdup(OpeningAddress1) : NULL;
}
You would need to free the previous value as long as the structure has been initialized properly, and also free the current Session->OpeningAddress when the structure is discarded.

Input Parsing in C & deciding where to forward

So I have the following project i need to work on for school. It involves a server/client communicating where the client sends requests to the server to get certain information. The server gets the req, parses it, and then sends a response based on the type of the request. For example:
GET /apple/fn/tom/ln/sawyer/a/25/id/1234 : This is a request to get the info for the following person who works at the Apple company (/apple):
fn (first name): Tom
ln (last name): Sawyer
a (age): 25
id (ID): 1234
Now the server should accept input, parse it, and return the information requested from its own database. implementing the server/client is not an issue. I need to know the best way to implement the algorithm to deal with input since not all requests would look like the one above. Other examples of requests:
GET /apple/i: This should return info about Apple company (i.e. address, phone number)
GET /apple/e: return number of employees in Apple company
GET /apple/e/id/1234: return info of employee in Apple company with the following id=1234 (which in our example would be Tom Sawyer) i.e. return first name, last name, age, address.
GET /apple/fn/tom/ln/sawyer/a/25/id/1234 : discussed above
SET /apple/fn/tom/ln/sawyer/a/25/id/5678 : update id of this employee to 5678
SET /apple/fn/tom/ln/sawyer/a/23 : update age of this employee to 23
...
I will have to implement different structs for req/response (i.e. a struct for req and another for response) as well as a different function for each of the different request/responses. BUT what is the best way to deal with parsing input && decide which function to send it to? I was told to look into using a parser-generator like Bison but to my understanding this would only help parse the input and break it up into pieces which is not that hard for me since I know I always have the "/" between fields so I can use the function:
strtok( input, "/" );
So main issue I have is how to decide where to send each request. So Assuming I have the following functions:
struct GetEmployeeInfoReq
{
char *fn;
char *ln;
int age;
};
struct GetEmployeeInfoResp
{
int house_num;
int street_num;
char *street_name;
char * postal_code;
int years_worked_here;
};
void GetEmployeeInfo( struct GetEmployeeInfoResp *resp, struct GetEmployeeInfoReq *req );
struct GetCompanyInfoReq
{
...
}
struct GetCompanyInfoResp
{
...
}
void GetCompanyInfo( struct GetCompanyInfoResp *resp, struct GetCompanyInfoReq *req );
Now I know that to call the first function I need the following request:
GET /apple/fn/tom/ln/sawyer/a/25/id/1234
and to call 2nd function I need the following:
GET /apple/i
My question is how to get this done? Off the top of my mind I'm thinking defining a variable for each possible field in the input req and using that so if this is my request:
GET /apple/e/id/1234
then I would have the following values defined and set to true:
bool is_apple = true;
bool is_employee = true;
bool is_id = true;
After I know that this request is:
GET /apple/e/id/<id_num>
AND NOT
GET /apple/e
so i can send it to the proper function.
Is this the correct approach as I'm lost on how to tackle this issue.
Thanks,
Get yourself a large piece of paper and make a diagram about the logic to get a grammar (not actually neede here, you could just parse it, but being a school assignment I assume that it is meant to be build up upon).
Some observations
every input starts with a /
every entry ends with a / except the last one
entries consist of characters and/or digits
empty entries gets you in trouble if you insist on using strtok (thanks to wildplasser, I missed that)
order matters?
Entries are
either key (one entry) or key/value (two consecutive entries).
In other words: the may or may not have an argument
Entries with a meaning
first entry is the company name (what do you do if that's all? Check assignment)
next entry is either
i print company info
e
without arguments: print #employees
with argument: print information about argument, argument must be correct
fn first name as a key, must have a value because of strtok, argument must be a string
ln last name as a key, must have a value because of strtok, argument must be a string
id id as a key, must have a value because of strtok, argument must be a string of digits (an integer so to say but it is still a string at that point) only
a age as a key, must have a value because of strtok, argument must be a string of digits (an integer so to say but it is still a string at that point) only
Examples:
/apple/e
/ start of input
apple company name. Must have an argument, so go on
e something with employers, my or may not have an argument so check.
EOI (end of input) that means that e has no arguments, so print the number of employees.
/apple/id/134
/ start of input
apple company name. Must have an argument, so go on
e something with employers, my or may not have an argument so check.
id is a key and must have a value, that means we need an argument, so check
1234 all digits which is correct value for id
EOI (end of input) no other things, so print the information you have about id-1234
/apple/fn/tom/ln/sawyer/a/25/id/1234
/ start of input
apple company name. Must have an argument, so go on
fn is a key, must have a value, check
tom the value for fn must be a string which it is, safe
ln is a key, must have a value, check
sawyer the value for ln must be a string which it is, safe
a is a key, must have a value, check
25 the value for ln must be a string of digits which it is, safe
id is a key, must have a value, check
1234 the value for ln must be a string of digits which it is, safe
EOI (end of input). The key for the database entry seems to be the name fn and ln, so read the entry tomsawyer and check if any of id or a is different and change accordingly. If nothing is different: check your assignment.
It might be good idea to build a struct with all of the informations and fill it while parsing (where I wrote "safe"). You need two main functions printIt(keys) and changeIt(key, value). Some things can be done immediately, like in my first example, some need further ado.
That's it, should be straightforward to implement.
EDIT a short example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ALL CHECKS OMMITTED!
#define DELIMITER '/'
// should resemble a row from the DB
typedef struct company {
char *comp_name;
unsigned int num_empl;
unsigned int empl_id;
unsigned int empl_age;
char *first_name;
char *last_name;
} company;
int main(int argc, char **argv)
{
company *entries;
char *input, *token;
size_t ilen;
if (argc < 2) {
fprintf(stderr, "Usage: %s stringtoparse \n", argv[0]);
exit(EXIT_FAILURE);
}
// work on copy
ilen = strlen(argv[1]);
input = malloc(ilen + 1);
strcpy(input, argv[1]);
entries = malloc(sizeof(company));
// skip first delimiter
if (*input == DELIMITER) {
input++;
ilen--;
}
token = strtok(input, "/");
if (token == NULL) {
fprintf(stderr, "Usage : %s stringtoparse \n", argv[0]);
exit(EXIT_FAILURE);
}
// first entry is the company name
entries->comp_name = malloc(strlen(token));
strcpy(entries->comp_name, token);
// mark empty entries as empty
entries->first_name = NULL;
entries->last_name = NULL;
entries->empl_age = -1;
entries->empl_id = -1;
// F(23)
entries->num_empl = 28657;
// only very small part of grammar implemented for simplicity
for (;;) {
token = strtok(NULL, "/");
if (token == NULL) {
break;
}
// "e" [ "/" "id" "/" number <<EOF>> ]
if (strcmp(token, "e") == 0) {
token = strtok(NULL, "/");
if (token == NULL) {
puts("Info about number of employees wanted\n");
// pure info, pull from DB (not impl.) and stop
break;
} else {
if (strcmp(token, "id") != 0) {
fprintf(stderr, "Only \"id\" allowed after \"e\" \n");
// free all heap memory here
exit(EXIT_FAILURE);
}
token = strtok(NULL, "/");
if (token == NULL) {
fprintf(stderr, "ERROR: \"id\" needs a number \n");
// free all heap memory here
exit(EXIT_FAILURE);
}
// does not check if it really is a number, use strtol() in prod.
entries->empl_id = atoi(token);
printf("Info about employee with id %d wanted\n", entries->empl_id);
// pure info, pull from DB (not impl.) and stop
break;
}
}
// "a" "/" number
else if (strcmp(token, "a") == 0) {
token = strtok(NULL, "/");
if (token == NULL) {
fprintf(stderr, "ERROR: \"a\" needs a number \n");
// free all heap memory here
exit(EXIT_FAILURE);
}
// does not check if it actually is a number, use strtol() in prod.
entries->empl_age = atoi(token);
printf("Age given: %d\n", entries->empl_age);
}
// "id" "/" number
else if (strcmp(token, "id") == 0) {
token = strtok(NULL, "/");
if (token == NULL) {
fprintf(stderr, "ERROR: \"id\" needs a number \n");
// free all heap memory here
exit(EXIT_FAILURE);
}
// does not check if it actually is a number, use strtol() in prod.
entries->empl_id = atoi(token);
printf("ID given: %d\n", entries->empl_id);
}
// "fn" "/" string
else if (strcmp(token, "fn") == 0) {
token = strtok(NULL, "/");
if (token == NULL) {
fprintf(stderr, "ERROR: \"fn\" needs a string \n");
// free all heap memory here
exit(EXIT_FAILURE);
}
entries->first_name = malloc(strlen(token));
strcpy(entries->first_name, token);
printf("first name given: %s\n", entries->first_name);
}
// "ln" "/" string
else if (strcmp(token, "ln") == 0) {
token = strtok(NULL, "/");
if (token == NULL) {
fprintf(stderr, "ERROR: \"ln\" needs a string \n");
// free all heap memory here
exit(EXIT_FAILURE);
}
entries->last_name = malloc(strlen(token));
strcpy(entries->last_name, token);
printf("last name given: %s\n", entries->last_name);
} else {
fprintf(stderr, "ERROR: Unknown token \"%s\" \n", token);
// free all heap memory here
exit(EXIT_FAILURE);
}
}
printf("\n\nEntries:\nCompany name: %s\nFirst name: %s\nLast name: %s\n",
entries->comp_name, entries->first_name, entries->last_name);
printf("Age: %d\nID: %d\nNumber of employees: %d\n",
entries->empl_age, entries->empl_id, entries->num_empl);
/*
* At this state you have information about what is given (in "entries")
* and what is wanted.
*
* Connect to the DB.
*
* If firstnamelastname is the DB-id and in the DB, you can check if
* the given ID is the same as the one in the DB and change if not.
*
* You can do the same for age.
*
* If firstnamelastname is not in the DB but ID is given check if the
* ID is in the DB, change firstname and/or lastname if necessary and
* congratulate on the wedding (many other reasons are possible, please
* check first or it might get really embarassing)
*/
// free all heap memory here
/* Disconnect from the DB */
exit(EXIT_SUCCESS);
}
Compiled with:
gcc -g3 -std=c11 -W -Wall -pedantic jjadams.c -o jjadams
try with
./jjadams "/Apple/fn/Tom/ln/Sawyer/a/10/id/3628800"
./jjadams "/Apple/e"
./jjadams "/Apple/e/id/1234"
./jjadams "/Apple/e/1234"

getpwuid_r and getgrgid_r are slow, how can I cache them?

I am writing a clone of find while learning C. When implementing the -ls option I've stumbled upon a problem that the getpwuid_r and getgrgid_r calls are really slow, the same applies to getpwuid and getgrgid. I need them to display the user/group names from ids provided by stat.h.
For example, listing the whole filesystem gets 3x slower:
# measurements were made 3 times and the fastest run was recorded
# with getgrgid_r
time ./myfind / -ls > list.txt
real 0m4.618s
user 0m1.848s
sys 0m2.744s
# getgrgid_r replaced with 'return "user";'
time ./myfind / -ls > list.txt
real 0m1.437s
user 0m0.572s
sys 0m0.832s
I wonder how GNU find maintains such a good speed. I've seen the sources, but they are not exactly easy to understand and to apply without special types, macros etc:
time find / -ls > list.txt
real 0m1.544s
user 0m0.884s
sys 0m0.648s
I thought about caching the uid - username and gid - groupname pairs in a data structure. Is it a good idea? How would you implement it?
You can find my complete code here.
UPDATE:
The solution was exactly what I was looking for:
time ./myfind / -ls > list.txt
real 0m1.480s
user 0m0.696s
sys 0m0.736s
Here is a version based on getgrgid (if you don't require thread safety):
char *do_get_group(struct stat attr) {
struct group *grp;
static unsigned int cache_gid = UINT_MAX;
static char *cache_gr_name = NULL;
/* skip getgrgid if we have the record in cache */
if (cache_gid == attr.st_gid) {
return cache_gr_name;
}
/* clear the cache */
cache_gid = UINT_MAX;
grp = getgrgid(attr.st_gid);
if (!grp) {
/*
* the group is not found or getgrgid failed,
* return the gid as a string then;
* an unsigned int needs 10 chars
*/
char group[11];
if (snprintf(group, 11, "%u", attr.st_gid) < 0) {
fprintf(stderr, "%s: snprintf(): %s\n", program, strerror(errno));
return "";
}
return group;
}
cache_gid = grp->gr_gid;
cache_gr_name = grp->gr_name;
return grp->gr_name;
}
getpwuid:
char *do_get_user(struct stat attr) {
struct passwd *pwd;
static unsigned int cache_uid = UINT_MAX;
static char *cache_pw_name = NULL;
/* skip getpwuid if we have the record in cache */
if (cache_uid == attr.st_uid) {
return cache_pw_name;
}
/* clear the cache */
cache_uid = UINT_MAX;
pwd = getpwuid(attr.st_uid);
if (!pwd) {
/*
* the user is not found or getpwuid failed,
* return the uid as a string then;
* an unsigned int needs 10 chars
*/
char user[11];
if (snprintf(user, 11, "%u", attr.st_uid) < 0) {
fprintf(stderr, "%s: snprintf(): %s\n", program, strerror(errno));
return "";
}
return user;
}
cache_uid = pwd->pw_uid;
cache_pw_name = pwd->pw_name;
return pwd->pw_name;
}
UPDATE 2:
Changed long to unsigned int.
UPDATE 3:
Added the cache clearing. It is absolutely necessary, because pwd->pw_name may point to a static area. getpwuid can overwrite its contents if it fails or simply when executed somewhere else in the program.
Also removed strdup. Since the output of getgrgid and getpwuid should not be freed, there is no need to require free for our wrapper functions.
The timings indeed indicate a strong suspicion on these functions.
Looking at your function do_get_group, there are some issues:
You use sysconf(_SC_GETPW_R_SIZE_MAX); for every call to do_get_group and do_get_user, definitely cache that, it will not change during the lifetime of your program, but you will not gain much.
You use attr.st_uid instead of attr.st_gid, which probably causes the lookup to fail for many files, possibly defeating the cacheing mechanism, if any. Fix this first, this is a bug!
You return values that should not be passed to free() by the caller, such as grp->gr_name and "". You should always allocate the string you return. The same issue is probably present in do_get_user().
Here is a replacement for do_get_group with a one shot cache. See if this improves the performance:
/*
* #brief returns the groupname or gid, if group not present on the system
*
* #param attr the entry attributes from lstat
*
* #returns the groupname if getgrgid() worked, otherwise gid, as a string
*/
char *do_get_group(struct stat attr) {
char *group;
struct group grp;
struct group *result;
static size_t length = 0;
static char *buffer = NULL;
static gid_t cache_gid = -1;
static char *cache_gr_name = NULL;
if (!length) {
/* only allocate the buffer once */
long sysconf_length = sysconf(_SC_GETPW_R_SIZE_MAX);
if (sysconf_length == -1) {
sysconf_length = 16384;
}
length = (size_t)sysconf_length;
buffer = calloc(length, 1);
}
if (!buffer) {
fprintf(stderr, "%s: malloc(): %s\n", program, strerror(errno));
return strdup("");
}
/* check the cache */
if (cache_gid == attr.st_gid) {
return strdup(cache_gr_name);
}
/* empty the cache */
cache_gid = -1;
free(cache_gr_name);
cache_gr_name = NULL;
if (getgrgid_r(attr.st_gid, &grp, buffer, length, &result) != 0) {
fprintf(stderr, "%s: getpwuid_r(): %s\n", program, strerror(errno));
return strdup("");
}
if (result) {
group = grp.gr_name;
} else {
group = buffer;
if (snprintf(group, length, "%ld", (long)attr.st_gid) < 0) {
fprintf(stderr, "%s: snprintf(): %s\n", program, strerror(errno));
return strdup("");
}
}
/* load the cache */
cache_gid = attr.st_gid;
cache_gr_name = strdup(group);
return strdup(group);
}
Whether the getpwuid and getgrgid calls are cached depends on how they are implemented and on how your system is configured. I recently wrote an implementation of ls and ran into a similar problem.
I found that on all modern systems I tested, the two functions are uncached unless you run the name service caching dæmon (nscd) in which case nscd makes sure that the cache stays up to date. It's easy to understand why this happens: Without an nscd, caching the information could lead to outdated output which is a violation of the specification.
I don't think you should rely on these functions caching the group and passwd databases because they often don't. I implemented custom caching code for this purpose. If you don't require to have up-to-date information in case the database contents change during program execution, this is perfectly fine to do.
You can find my implementation of such a cache here. I'm not going to publish it on Stack Overflow as I do not desire to publish the code under the MIT license.

Does sys function call "stat" change my file?

I am currently trying to make "C" a little bit more scripting language like for myself. I writing my program specific code in a *.so file reload this file at runtime and execute the new code i wrote.
The problem i am facing is the result of the function "stat". Everytime i ask if the SO file has been modified via "stat(filename,statbuf)" the result stat->mtim always seems to have been changed. As result i continously reload my code in each loop run.
I have assumed that if no file change to a file happend st_mtime has to be always the same. Am i wrong?
Here the function how i retrieve the value st_mtime:
inline timespec LinuxGetLastWriteTime(const std::string& filename) {
struct stat *buf;
stat(filename.c_str(), buf);
return buf->st_mtim;
}
And here where i check if i have to reload:
timespec NewSOWriteTime = LinuxGetLastWriteTime(SoSource);
if ( Game.last_modification != NewSOWriteTime ) {
LinuxUnloadGameCode(&Game);
Game = LinuxLoadGameCode(SoSource, "libCode_temp.so");
}
and my two overloads of the != and <:
bool operator<(const timespec& lhs, const timespec& rhs) {
if (lhs.tv_sec == rhs.tv_sec)
return lhs.tv_nsec < rhs.tv_nsec;
else
return lhs.tv_sec < rhs.tv_sec;
}
bool operator!=(const timespec& lhs, const timespec& rhs) {
if (lhs.tv_sec == rhs.tv_sec)
return lhs.tv_nsec != rhs.tv_nsec;
else
return lhs.tv_sec != rhs.tv_sec;
Any Idea why this could can happen
The code you use:
struct stat *buf;
stat(filename.c_str(), buf);
return buf->st_mtim;
is strange, to say the least. You got unlucky and it didn't crash instantly, but noone really knows where it writes results; probably overwrking some other important data on the way. You should allocate buf yourself and pass its address to stat, e.g.:
struct stat buf = {0}; // or memset(0)
stat(filename.c_str(), &buf);
return buf.st_mtim;
You probably should also check error status of stat, but if buffer is zeroed it will just return 0 which may be fine.

C Struct read/ write garbage value to file

I am diving into C after long time and struggling with reading and writing struct to the simple text file. I debuged this prog and I found out its reading and writing garbage value to the file. Can someone help me. Here is my code
#define MAX_UserName_LEN 16
#define MAX_Password_LEN 8
#define MAX_FileName_LEN 32
struct userDetails
{
char userName[MAX_UserName_LEN];
char password[MAX_Password_LEN];
};
int registration(struct userDetails userInfo)
{
FILE *userDb;
userDb= fopen("UserDataBase.txt","a");
if(fwrite(&userInfo,sizeof(userInfo),1,userDb))
{
fclose(userDb);
return 1;
}
else
{
return 0;
}
}
int authenicate(struct userDetails userInfo)
{
FILE *userDb;
struct userDetails temp;
userDb = fopen("UserDataBase.txt","r");
while(!feof(userDb))
{
fread(&temp,sizeof(temp),1,userDb);
if (temp.userName==userInfo.userName && temp.password==userInfo.password)
{
printf("Logged In Sucessfully");
return 1;
}
}
return 0;
}
In main function, I an just declaring one struct variable and accepting user input into that struct and passing it to both above mentioned functions.
The first major problem I see is here:
if (temp.userName==userInfo.userName && temp.password==userInfo.password)
You are trying to compare strings with ==. You need to use strcmp() instead:
if (strcmp(temp.userName, userInfo.userName) == 0 &&
strcmp(temp.password, userInfo.password) == 0)
I'm not sure if this has anything to do with the "garbage" you're getting, but it's definitely an error.
As your code stands right now, it will never enter the if-statement.
Write a short code, which prints the userlist, so you'll see wheter the file contains garbage or not.
Anyway, passwords should be scrambled somehow. Even a dumb solution is better than nothing, just to make it non-readable for human eyes. Say, for (n = 0; n < strlen(pwd); n++) pwd[n] ^= 0x55;.

Resources