I am creating a log in system. Just the basic, username and pass.
=====Log in===
user: abcd
pass: ****
==============
max 4 alphanumeric characters.
struct account
{
user[5];
pass[5];
}s;
For example in my database.txt file I already have this.
abcd //user
1234 //pass
So in the main its like this:
main()
{
FILE *fp;
fp=fopen("account.txt","r");
char user[5],pass[5];
printf("enter user: ");
gets(user);
printf("enter pass: ");
pass[0] = getch();
printf("*"); //doing this for
pass[1] = getch(); //password security
printf("*"); //asterisk(*)
pass[2] = getch();
printf("*");
pass[3] = getch();
printf("*");
pass[4] = '0';
getch();
while(fread(&s,sizeof(s),1,fp)==1);
{
if(ferror(fp))
{
printf("error");
}
else if (strcmp(s.user,user) == 0 && strcmp(s.pass,pass) == 0)
{
printf("success!");
}
else
{
printf("invalid");
}
}
getch();
}
problem is it is not working. When I put the correct pass it will always say invalid. but when I use
gets(pass); rather than the pass[0]=getch(); it works perfect.
Is this the correct way of doing the password security and reading it?
First, this is not a particularly good idea, as it is extremely insecure. Several decades of lessons on how not to do this have been learned by the industry, and you are on track to re-learn those the painful way.
As to your specific problem, you are not null terminating the pass array before running a null-terminated string comparison on it.
Declare it with 5 elements, and set the fifth - pass[4] - to 0.
Related
How would I convert this code to use while loops instead of recursion?
void game(void)
{
int answer;
printf("%s", Questions[level]);
scanf("%d", &answer);
if (level < 8) {
if (is_right(level, answer)) {
printf("Good Job!\n");
level += 1;
game();
}
else {
printf("Sorry, you got the wrong answer. Try Again! \n");
sleep(1);
system("clear");
level = 0;
game();
}
}
else {
printf("Great Job, You Won!");
}
}
I tried starting with a while loop and trying to work backwards, but I got lost in the sea of code
There is a couple of "strange" things in your program that I'll get back to later but to start with let's focus on the question:
How would I convert this code to use while loops instead of recursion?
There are many ways to do that...
The current recursive calls, i.e. game();, takes no arguments, nor does it use a return value. So a very simple way to get rid of recursion and keeping the exact same functionality could be:
Add a while(1) loop around all the existing code
Replace the current recursive calls with a continue; statement
Add a break; statement when the loop is to terminate
That would look like:
void game(void)
{
while(1) { // Add a while loop
int answer;
printf("%s", Questions[level]);
scanf("%d", &answer);
if (level < 8) {
if (is_right(level, answer)) {
printf("Good Job!\n");
level += 1;
// game();
continue; // Start a new round of the game
}
else {
printf("Sorry, you got the wrong answer. Try Again! \n");
sleep(1);
system("clear");
level = 0;
//game();
continue; // Start a new round of the game
}
}
else {
printf("Great Job, You Won!");
break; // End the game by breaking out of the while loop
// This could also be a return; statement
}
}
}
The above solution preserves the structure of the original program. If we allow some (minor) restructuring, we can do a little better.
void game(void)
{
while(1) {
int answer;
printf("%s", Questions[level]);
scanf("%d", &answer);
// Check if the game has finished
if (level >= 8) {
printf("Great Job, You Won!");
return; // or break;
}
if (is_right(level, answer)) {
printf("Good Job!\n");
level += 1;
} else {
printf("Sorry, you got the wrong answer. Try Again! \n");
sleep(1);
system("clear");
level = 0;
}
}
}
Instead of checking for "shall game continue" the above version checks for "has game finished" and - if so - it returns. By doing that we no longer need the explicit continue; statements.
Now getting back to the "strange" things in your program:
When a user wins the game (i.e. level reach 8), the code will still ask one more question and once the answer has been entered, the program finish. That is probably not intended...
Further, the only way to finish the game is to win the game (i.e. answer correct a number of times in a row). I would expect a way for the user to say "I give up"
Finally there is a serious problem with your code that may lead to errors like program crash or infinite loop. Always, always, always, check the return value of scanf !!! (see end-note)
Fixing those things and doing a little more restructuring could lead to a program like:
void game(void)
{
level = 0; // Assuming a new game always starts a level zero
while(1) {
int answer;
printf("%s", Questions[level]);
if (scanf("%d", &answer) != 1) {
// Wrong input or input error
// Add error handling... but for now, just terminate
exit(1);
}
// Let the user end the program with a negative input
if (answer < 0) {
printf("Sorry to see you leave before finishing the game. Bye.\n");
return 0;
}
if (is_right(level, answer)) {
printf("Good Job!\n");
level += 1;
// Check if the game has finished
if (level == 8) {
printf("Great Job, You Won!");
return;
}
} else {
printf("Sorry, you got the wrong answer. Try Again! \n");
sleep(1);
system("clear");
level = 0;
}
}
}
End-note:
While it's true that the return value from scanf shall be checked, the better advice would be:
Never use scanf.
At the surface scanf looks like an easy way to get user input but the truth is that it has so many pitfalls that only real experts are able to use it (and they probably wont). The number of SO questions where (incorrect use of) scanf is the root cause of a problem is extreme. And they keep coming...
So forget that you ever heard about scanf. If you do like the features of scanf, you will (nearly) always do better by using fgets followed by sscanf.
It is hard to call it recursion.
void game(void)
{
int answer;
while (level < 8)
{
printf("%s", Questions[level]);
if(scanf("%d", &answer) != 1){ /* handle error */}
if (is_right(level, answer))
{
printf("Good Job!\n");
level += 1;
}
else
{
printf("Sorry, you got the wrong answer. Try Again! \n");
sleep(1);
system("clear");
level = 0;
}
}
printf("Great Job, You Won!");
}
switch(res)
{
case 1:
printf("Enter password: ");
scanf("%s", password);
int value=strcmp(rpassword , password);//when comparing strings
if(value==0)
{
printf("Welcome to the Hospital Management system \n");
}
else
{
printf("Re-Enter Password \n");
}
break;
default:
printf("Welcome \n");
break;
}
Don't do that.
Seriously, you need to make your operating system or dedicated libraries handle it, don't mess with passwords.
In your program you would need to:
not hardwire the password (do not have a global variable or a #define,
otherwise the password is
retrivable by searching it with strings, disassembler/decompiler or hex-editors).
hash it, if you save it on the disk, save the hash of the password, do not
check directly with strcmp, it mean that you're saving it in clear-text,
which is a deprecated procedure from a lot of time.
manage to have an anti brute-force mechanism
don't use scanf("%s", input);, it would open your program to buffer
overflows, because you're not checking the length of the input.
and some other details that your operating system is already taking in
consideration (e.g. with PAM).
I think that you want to generally handle a wrong string input, to do so you need
to do something like the following:
#include <string.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int r = 0;
char buffer[5];
do {
printf("Enter yes: ");
fflush(stdout);
fgets(buffer, sizeof(buffer), stdin);
buffer[3] = '\0';
printf("User inserted %s\n", buffer);
r = strcmp("yes", buffer);
if (r != 0)
printf("please say yes\n");
} while (r != 0);
printf("Welcome\n");
return 0;
}
If you need to read a password, please use a stronger and tested method, such as PAM on Linux
similar to this answer: PAM authenticate a user in C
You can use a do-while loop as follows:
int value;
do
{
printf("Enter password: ");
scanf("%s", password);
value=strcmp(rpassword , password);//when comparing strings
if(value==0)
{
printf("Welcome to the Hospital Management system \n");
}
else
{
printf("Re-Enter Password \n");
}
} while(value != 0);
You can run an infinte loop like this : while(1)
And if the password is correct just break the loop else it will continue to ask the user.
I am a beginner programmer taking a free class and I am having a lot of trouble with a simple Meyer's encryption scheme for security based encryption and decryption. I cannot work on the decryption because I cant even get the encryption to work. We are required to add necessary prompts etc to make sure the correct things are entered by the user. Here is my code:
int main (void)
{
const int N = 10;
char message [N];
char processed[N];
char selection;
void encrypt_msg(char msg[],char encrypted[]);
printf("Please enter a message: ");
fgets (message, N, stdin);
printf("%s\n",message);
printf("Would you like to encrypt <E>, or decrypt <D> this message?");
scanf(" %c\n",&selection);
if (selection == 'E')
{
encrypt_msg(message,processed);
printf("%s\n",processed);
return 0;
}
if (selection != 'E')
{
printf("Invalid selection, please enter <E> or <D> ");
}
}
void encrypt_msg(char msg[],char encrypted[])
{
int i;
int NL;
for (i=0;msg[i]!='\0';i++)
{
while (msg[i]<'z'&&msg[i]>'A')
{
NL=msg[i]+i+1;
while (NL<'z')
{
NL=NL;
}
while(NL>'z')
{
NL=NL-26;
}
encrypted[i]=msg[i]+1;
}
}
}
The problem is that when the user inputs "E", the program will immediately go to the "invalid input" if statement and bypass the actual encryption function. It may be doing something entirely different but I don't know because I am horrible. 'NL' is for the new letter that is to replace the old letter based on the M.E.S.S key.
have you tried scanf("%c",&selection); without '\n' ?
First of all a great idea would be indenting, helps a lot especially in lengthy projects/scripts.
Moreover try simplifying you if statements for the sake of your own debug. Now comes the fun part, after rewriting the critical section of your code to meet my "habits" seems like fully working!
What I added/removed was:
if - else statement instead of the old one;
fflush(stdin) since seemed to lag on my machine;
removed that peculiar "\n" from the scanf() section.
int main()
{
int N = 10;
char message [N];
char processed[N];
char selection;
printf("Please enter a message: ");
fgets (message, N, stdin);
printf("%s\n",message);
fflush(stdin);
printf("Would you like to encrypt <E>, or decrypt <D> this message?");
scanf("%c",&selection);
if (selection == 'E' || selection == 'e')
{
printf("Im into it\n");
//Do the actual function calls below
}
else if(selection == 'D' || selection == 'd')
{
// Do what you would do to decrypt the msg
}
else
{
printf("Invalid selection, please enter <E,e> or <D,d> ");
}
return 0;
}
I am trying this login program in C but due to some reasons the program gets stuck in infinity loop the moment user name is entered.I have double checked my code but could not find anything wrong in it.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char *name="bob"; //test data
char *password="pas";
int user_name()
{
fflush(stdin);
char *c[10],*p[10];
printf("user name enter\n");
if(fgets(c,10,stdin)) //check if any user data entered
{
if(name==NULL)
{
printf("welcome user created\n");
strcpy(name,c);
fflush(stdin);
printf("create a password\n");
fgets(password,10,stdin);
return 1;
}
else
{
if(strcmp(name,c)==0) //if user input matched existing username
{
fflush(stdin);
printf("enter password");
fgets(p,10,stdin); //take in password
if(strcmp(p,password)==0) //compare password
return 1;
}
return 0;
}
}
int main()
{
int t=0;
t=user_name();
if(t==1)
printf("welcome");
else
printf("sorry");
return 1;
}
Please help me in finding the problem.
getting the name should be scanf("%s",name).
To copy sting in C use strncpy or similar functions.
fflush(stdin) is UB.
c is a pointer to a char - it will just store address of a char variable. But it itself is not a char. You need to allocate memory for that.
To allocate you can do this:-
char *c = malloc(sizeof(*c)*MAXLEN);
if( c == NULL){
// error
}
To get the username you should do something like this
char name[MAXLEN];
if(fgets(name, MAXLEN, stdin)){
// name read in `name`
}
Also you can logically seperate your code like this:-(these are the logical steps)
Start the program
Get username
Validate
Password validation
Necessary hints:
If you want to use the username password in different instance of the program then you have to store it somewhere (be it files or database).
If that's not what you want, then you can simply use a while loop to initiate multiple cases where you take user input. Otherwise how would you verify the password or username set?
As per the modified code:-
You don't need that literal bob or pas if you are taking input for the first time.
Use simple input first. char c[10] will do. You have declared an array of character pointers.(which can't be used unless you allocate some memory to those pointers).
Initial solution:-
#define MAXLEN 60
char name[MAXLEN]; //sample data(Just for testing)
char pas[MAXLEN]; //sample data
int firstime = 1;
int user_name()
{
char name1[MAXLEN];
char pas1[MAXLEN];
if(firstime){
printf("user name enter\n");
scanf("%s",name);
printf("password enter\n");
scanf("%s",pas);
firstime = 0;
return 1;
}
else
{
printf("user name enter\n");
scanf("%s",name1);
printf("password enter\n");
scanf("%s",pas1);
if(strcmp(name,name1) == 0 && strcmp(pas,pas1) == 0)
return 1;
else
return 0;
}
}
Now this is what is the initial code looks like :-
You can replace scanf calls with fgets().
if(fgets(name,MAXLEN,stdin)==NULL)
{
//error
}
Also as mentioned before you can try to modify the solution to contain more modular solution but taking the reusable portions and making a function out of it.
I am trying to build a program which will take in a list of login details (usernames and passwords) from a file and allow you the option to enter a username and password which are compared with the approved logins and a result is given. In my strcmp I am receiving access violation error 0xC0000005.
#include <stdio.h>
#include <conio.h>
#include<stdlib.h>
FILE *fptr;
void main();
void openFile();
void closeFile();
char approvedUsrnames[3][6];
char approvedPassword[3][6];
void main()
{
char userPassword[6], usrname[6], inputChar, fileString[6];
int i;
openFile();
int numofLogins= 3;
if (fptr != NULL)
{
printf("\nReading file with scanf\n");
while (!feof(fptr))
{
for (i = 0; i < 3; i++) {
fgets(approvedUsrnames[i], 6, fptr);
fgets(approvedPassword[i], 6, fptr);
}
}
closeFile();
}
printf("Enter User name: ");
scanf("%s",usrname);
printf("Enter the password <any 6 characters>: ");
for (i = 0; i<6; i++)
{
inputChar = _getch();
userPassword[i] = inputChar;
inputChar = '*';
printf("%c", inputChar);
}//obfuscate the input to the user
/*If you want to know what you have entered as password, to be removed*/
printf("\nYour password is %s:", userPassword);
for (i = 1; i < 3; i++) {
printf("\Username is good %s\n", approvedUsrnames[i]);
if (strcmp(approvedUsrnames[i], usrname == 0)){
printf("\Username is good\n");
if (strcmp(userPassword, approvedPassword[i]) == 0) {
printf("\nPassword is good\n");
}//end nested if
else {
printf("\nPassword is not match\n");
}
}//end if
}//end for
_getch();
}
void openFile()
{
fptr = fopen("approvedLogins.dat", "r");
if (fptr == NULL)
{
printf("Error opening file ! \n");
}
else {
printf("Login file read successfully ! \n");
}
}
void closeFile()
{
fclose(fptr);
}
#anthonygordon
It is very likely that the strings usrname and userPassword aren't being terminated with '\0' (null terminator) a) as the scanf() may attempt to fill in more chars than usrname can capture b) for loop has to iterate only 5 times so that userPassword[5] is to be explicitly set to '\0'. (If the expectation is to use 6 character long username and password, then change the length of array from 6 to 7 and make sure array[6] is filled with '\0') (Remember in 'C' array subscripts goes as 0..(arraysize-1))
Also, once the user name and password matches, break-out from the loop.
You picked specific lengths for your username and password character arrays. This means that you know the amount of characters you want to compare.
In such a case you do not need to add a '/0' to your character array. Simply use the strncmp() function and specify the number of characters to compare in the second parameter.
See: http://www.tutorialspoint.com/c_standard_library/c_function_strncmp.htm
Just a tip:
Test after every bit of code that you add. This way it is easy to know what code caused the problem. Only when you get really experienced (perhaps 4+ years of coding) can you be brave and write more code before testing.