C project for fun - c

I am new to coding (I just started this year), so please forgive me for any dumb mistakes. However, my goal is to make some straightforward code to have users enter their username and password. I would like the username to have 8 characters,1 uppercase, 1 lowercase, 1 digit, and 1 symbol. I thought my code was good but I keep running into an issue where I keep getting an error that says, "array must be initialized with a brace enclosed initializer". If you can find where I can improve, and what the issue might be it would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
char username[20];
char password[20];
bool verify_password(char *password)
{
int length = strlen(password);
if (length < 8) return false;
bool has_upper = false;
bool has_lower = false;
bool has_digit = false;
bool has_symbol = false;
for (int i = 0; i < length; i++)
{
if (isupper(password[i])) has_upper = true;
if (islower(password[i])) has_lower = true;
if (isdigit(password[i])) has_digit = true;
if (ispunct(password[i])) has_symbol = true;
}
if (!has_upper) return false;
if (!has_lower) return false;
if (!has_digit) return false;
if (!has_symbol) return false;
return true;
}
int main()
{
printf("please enter your new username:\n");
scanf("%s", username);
printf("please enter your password(must be 8 characters,1 uppercase, 1 lowercase, 1 digit, and 1 symbol):\n");
scanf("%s", password);
char password[strlen(password)] = password;
bool result = verify_password(password);
if (result)
{
printf("password has been verified\n");
}
else
printf("missing element described");
printf("welcome to your account %s!, your password is %s", username, password);
return 0;
}

The compiler is saying that arrays need to be initialized with = { ... };
char password[strlen(password)] is an array, specifically a variable-length array (VLA). However, these arrays are special since they cannot get initialized at all. You have to set their values at run-time
Furthermore, it has to be char password[strlen(password)+1] so there's room for the null terminator.
Furthermore, you need to assign a value to a string using strcpy, not with the = operator.
Furthermore, you cannot have several variables with the same name. Or well you can, but in case of char password[strlen(password)] = password;, the password refers to the local variable, not the global one. It's a bad idea to use global variables in general and this would be one of many reasons why.
Overall you cannot do C programming by trial & error. There's no "take a chance and type something that looks ok", you need to actually know what every single thing you write does and that it is valid C.

Related

Using OR in statements with arrays, (C)

I've been trying to make a username and password interface and I was wondering if it was possible to have an or statement within strcmp and if I could also use all values of the array within 1 string, Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int u, p;
char Iuser[50],Ipass[50];
char user[3][50] = { "user1", "user2", "user3" };
char pass[3][50] = { "pass1", "pass2", "pass3" };
printf("\n Enter your username:");
gets(Iuser);
u = strcmp(user[0|1|2], Iuser);
if (u == 0) {
printf("\n Enter your password");
scanf("%s", &Ipass);
} else {
printf("\n Invalid Username, Try Again !");
}
}
No, you can't do like that in C.
I'm stealing Aconcagua's comment about what it actually does:
user[0|1|2] first calculates 0|1|2, then accesses the array. Result of bitwise OR-ing 0, 1 and 2 is 3, though, which already is out of bounds of your user array, thus undefined behaviour
So, instead of
u=strcmp(user[0|1|2],Iuser);
if(u==0) {
You should do:
#include <stdbool.h>
bool u = strcmp(user[0], Iuser) == 0 ||
strcmp(user[1], Iuser) == 0 ||
strcmp(user[2], Iuser) == 0;
if(u) {
If the array of users is long or the number of users is not known at compile-time:
bool u = false;
for(int i = 0; i < number_of_users; ++i) {
if(strcmp(user[i], Iuser) == 0) {
u = true;
break;
}
}
if(u) {
Note: Don't use bitwise OR, |, for these comparisons. Using the logical OR, ||, enables short-circuit evaluation so that it stops testing as soon as one condition is true, just like the loop above which breaks out as soon as one condition has been found true.
strcmp cannot be used this way: user[0|1|2] evaluates to user[3], which accesses an element of the array beyond the end of the array: strcmp() will have undefined behavior when it reads from this place.
The C library does not have a generic function to locate a string in an array, so you should write:
u = strcmp(user[0], Iuser) && strcmp(user[1], Iuser) && strcmp(user[2], Iuser);
Which is quite verbose and specific.
Note that you should always ask for a password to avoid giving information about user names to an intruder, so the code should be modified as:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char Iuser[50];
char Ipass[50];
char user[3][50] = { "user1", "user2", "user3" };
char pass[3][50] = { "pass1", "pass2", "pass3" };
int nusers = sizeof(user) / sizeof(user[0]); // number of users
int u;
for (;;) {
printf("\n Enter your username:");
if (scanf("%49s", Iuser) != 1)
return 1;
printf("\n Enter your password");
if (scanf("%49s", Ipass) != 1)
return 1;
for (u = 0; u < nusers; u++) {
if (strcmp(user[u], Iuser) == 0 && strcmp(pass[u], Ipass) == 0)
break;
}
if (u < nusers)
break;
printf("\n Invalid Username and/or password, Try Again !");
}
// user has been authenticated.
// ...
return 0;
}
Note also that password should be read without echoing the characters to the terminal, which is tricky but can be achieved on unix systems via getpass:
#include <pwd.h>
#include <unistd.h>
char *getpass(const char *prompt);
Passwords should not be stored in clear text as you do, nor as encrypted text because they would be too easy to find. Computing a cryptographic hash is recommended, in addition to more advanced techniques.
You should do
u=strcmp(user[0],Iuser)!=0 && strcmp(user[1], Iuser)!=0 && strcmp(user[2],Iuser)!=0;
if(u==0) {
//User exists so ask password
because strcmp accepts only two strings to compare. If you do a OR as u said it would be something strange like bitwise operation inside char arrays, I doubt it would ever compile and we don't want to do that.
Have a good day.

Basic Username/Password Code not working in C - Segmentation Fault

I've just started learning C 2 days ago and have tried to write a code that prompts the user to submit a username and password and then cross-references the input with stored data. The idea is that if the inputted username and password match then "Access Granted" would be printed and if not, "Access Denied".
However, I keep receiving "Access Denied.Segmentation fault" whenever I test the code with inputs. Any thoughts on why this would happen? Attaching my code below for reference:
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <cs50.h>
int N;
typedef struct
{
string Username;
string Password;
}
LoginInfo;
int main(void)
{
LoginInfo code[N];
code[0].Username = "Agent X";
code[0].Password = "1314XN";
code[1].Username = "Agent Y";
code[1].Password = "1315YN";
code[2].Username = "Agent Z";
code[2].Password = "1316ZN";
code[3].Username = "Director A";
code[3].Password = "1414AN";
code[4].Username = "VP A";
code[4].Password = "1628VPN";
string User = get_string("Username: ");
string Pass = get_string("Password: ");
for (int i = 0; i < N; i++)
{
if((strcmp(code[i].Username, User) == 0) && (strcmp(code[i].Password, Pass) == 0))
{
printf("Access Granted.\n");
return 0;
}
}
printf("Access Denied.");
return 1;
}
You've defined int N; but didn't initialize it. Since it's at global scope it's given a value of 0.
When you reach the line LoginInfo code[N]; the value of N is still 0 so the array is given a size of 0. Accessing any elements of the array leads to undefined behavior and is the likely source of the fault.
You need to initialize N or otherwise give it a reasonable value before it's used. For example:
int N = 5; // Initialize this!
With this change your code compiles cleanly and runs. Demo on Compiler Explorer
You aren't defining a value for N so if you want N to be 5 change this to
#define N 5
Without a value for N, it is 0 (likely), and so the array is of size 0 and you will always get a segmentation fault.

crypt function in C breaking password string in for loop

I am new to C, and I have been going through the CS50 course to learn some basics. I have been trying to solve the challenge which requires you to make a simple password cracker, but I ran into a problem which prevents me from writing a function program: every time I call the crypt function in my for loop, it somehow breaks my password string that I am iterating through.
I have tried making a copy of the password string, and passing that as an argument to crypt; I have also tried moving the crypt call into a separate function and calling that from the loop (as well as the combination of the two)
#define _XOPEN_SOURCE
#include <unistd.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
string buildLetterDictionary();
int main(int argc, string argv[])
{
if (argc == 2)
{
printf("Two arguments, starting test...\n");
char password[2];
string letters = buildLetterDictionary();
for(int i = 0; i < 5; i++)
{
password[0] = letters[i];
password[1] = '\0';
printf("Password: %s\n", password);
string hashed = crypt(password, "50");
printf("\n%i\nOriginal: %s\nHashed: %s\n", i, password, hashed);
}
return 0;
}
else
{
printf("Usage: ./crack hash");
return 1;
}
}
string buildLetterDictionary()
{
char letters[27];
for(int i = 65; i < 91; i++)
{
letters[i-65] = i;
}
letters[26] = '\0';
string letter = letters;
return letter;
}
if I comment out the lines:
string hashed = crypt(password, "50");
printf("\n%i\nOriginal: %s\nHashed: %s\n", i, password, hashed);
The code works as expected, and produces the output:
A
B
C
D
E
But if I leave those lines in, the password is printed out as 'A' with the hash "50pe4e2XTIS/g" the first time, but every subsequent time is printed out as "" with the hash "50sXZPq5euCxs"
Please let me know what the underlying problem is, so that I may work towards resolving it! Thanks for any help in advance!
I am guessing here that cs50.h contains some definitions like a type alias from char * to string that the professor is giving you for simplicity.
If that is true, then buildLetterDictionary() cannot work, because you are doing:
char letters[27];
...
char * letter = letters;
return letter;
This means you are returning the address of a local variable, which will be destroyed as soon as you leave the function.

Cannot print a function's return value in another function in C

I have a function named Login() that reads a username(ex. "John") and then create a password that is the username itself with each letter upper or lower in random (ex. "JoHn")inside a new function called password() .However when I try to print the password in Login() as a return statement from password() it prints null;
This is the function that returns the password :
void Login()
{
char passwd[20];
char name[20];
printf(" Please enter your username : \n");
do
{
scanf(" %s",&name);
}while(strcmp(name,"John")!=0);
printf("Your password is : %s\n",password(name));
printf("Please enter your password : \n");
do
{
scanf(" %s",&passwd);
}while(strcmp(passwd,password(name))!=0);
}
And this is the function that returns the password :
char password( char pass[])
{
int i;
int k;
for(i=0;i<strlen(pass);i++)
{
k= rand()%2;
if(k==1)
{
pass[i]=toupper(pass[i]);
}
else{
pass[i]=tolower(pass[i]);
}
}
return pass;
}
Now when I run Login() in main i get
"Your password is : (null)"
How can I fix this problem ?
The primary issue: Your password() function actually return a char, whereas it is supposed to return a pointer to the first element of a char array (modified one).
That said, there are other issues.
You call password(name) multiple times (in do...while loop), whereas, your input is supposed to be validated against the result of the first call. As in every call, the returned string is randomized, successive calls will return different results. You need to store the result of the first call and compare the input against it.
scanf(" %s",&name); should be scanf("%19s",name);, because
The 19 will length-limit the input, avoiding possible buffer overflows.
The array type, in most cases, automatically decays to a type as pointer to the first element - use of & is not needed.
Same for password input also.
EDIT:
Here is a working version of the code: Live version
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char* password( char pass[])
{
int i;
int k;
for(i=0;i<strlen(pass);i++)
{
k= rand()%2;
if(k==1)
{
pass[i]=toupper(pass[i]);
}
else{
pass[i]=tolower(pass[i]);
}
}
return pass;
}
int main(void)
{
char passwd[20];
char name[20];
printf(" Please enter your username : \n");
do
{
scanf("%19s",name);
}while(strcmp(name,"John")!=0);
char * res = password(name);
printf("Your password is : %s\n",res);
do
{
printf("Please enter your password : \n");
scanf("%19s",passwd);
}while(strcmp(passwd,res)!=0);
return 0;
}

Password Function Error

void main()
{
Password();
}
void Password()
{
//declare local variables//
char cPassCode[] = "String";
int iFlag, iComparison = 0;
//Run the code to check the password//
while (iFlag = 1)
{
printf("Please enter the password: ");
scanf("%s", cPassCode);
iComparison = strcmp(cPassCode,"A23bc5");
if (iComparison == 0)
{
Header();
ArrayPrinter(Array);
iFlag = 0;
}
else
{
printf("Wrong password");
iFlag = 1;
}
}
}
I've got this code for my program. The whole program runs fine but it goes through the loops again. I think it has to do with my while loop. If I try changing the condition, the program doesn't run at all. Any ideas?
One problem is here: while (iFlag = 1) you're not comparing iFlag to 1, you're setting it to 1. One correct way to do this is while (iFlag == 1) but a safer way to phrase that is: while (1 == iFlag) so that the compiler will pick up when you make the ==/= error next time. But the best way of all, since iFlag is being used as a boolean, is to simply do while (iFlag)
Next, you need to initialize iFlag before you use it:
int iFlag = 1, iComparison = 0;
And finally, this is not a good way to initialize cPassCode:
char cPassCode[] = "String";
As you don't know how many characters the user will type in -- use a larger value, something like:
#define MAXIMUM_INPUT_SIZE 1024
// ...
char cPassCode[MAXIMUM_INPUT_SIZE];
Your while loop sets iFlag = 1, so it is always true. You want the comparison operator instead iFlag == 1. Also, you should initialize iFlag to 1 instead of zero so that your new loop works. Lastly, you should malloc cPassCode, though that isn't making your program crash (probably).

Resources