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

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.

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.

C project for fun

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.

need help to find segmentation fault error

can someone help me to find what cause segmentation fault in my program, I used the gdb but I cannot find which line that cause the error.
Array* Merge(Array *arr1, Array *arr2)
{
int i,j,k;
i=j=k=0;
Array *arr3 = (Array*)malloc(sizeof(Array));
arr3->size = arr1->size + arr2->size;
arr3->length = arr1->length + arr2->length;
while(i<arr1->length && j<arr2->length)
{
if(arr1->A[i] < arr2->A[j])
arr3->A[k++]=arr1->A[i++];
else
arr3->A[k++]=arr2->A[j++];
}
for(;i<arr1->length;i++)
arr3->A[k++]=arr1->A[i];
for(;j<arr2->length;j++)
arr3->A[k++]=arr2->A[j];
return arr3;
}
#include <stdio.h>
#include <stdlib.h>
#include "array1.h"
int main()
{
Array arr,arr1,*arr2;
arr.size=10;
arr.length=5;
arr1.size=10;
arr1.length=5;
arr.A=(int*)malloc(arr.size*sizeof(int));
arr1.A=(int*)malloc(arr.size*sizeof(int));
printf("\n enter elements of arr\n");
for (int i=0;i<arr.length;i++)
scanf("%d",&arr.A[i]);
/**********************************************/
printf("\n enter elements of arr1\n");
for (int i=0;i<arr1.length;i++)
scanf("%d",&arr1.A[i]);
arr2=Merge(&arr, &arr1);
display(*arr2);
return 0;
}
here is the result of the gdb
enter image description here
In Merge you don't allocate any space for arr3's data (probably a member called A looking at the other code)
It would help to see the rest of the code (especially the declaration of Array) but I suspect arr3->A is an uninitialised pointer.

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.

Another C question

I have a piece of code shown below
#include <stdio.h>
#include <stdlib.h>
void Advance_String(char [2],int );
int Atoi_val;
int Count_22;
int Is_Milestone(char [2],int P2);
char String[2] = "0";
main()
{
while(1)
{
if(Is_Milestone(String,21)==1)
{
if(atoi(String)==22)
{
Count_22 = Count_22 + 1;
}
}
Atoi_val = atoi(String);
Advance_String(S,Atoi_val);
}
}
int Is_Milestone(char P1[2],int P2)
{
int BoolInit;
char *Ptr = P1;
int value = atoi(Ptr);
BoolInit = (value > P2);
return BoolInit;
}
void Advance_String(char P1[2],int Value)
{
if(Value!=7)
{
P1[1] = P1[1]+1;
}
else
{
P1[1] = '0';
P1[0] = P1[0]+1 ;
}
}
Now my problem is Count_22 never increments as the char increments never achieves the value 21 or above.Could anyone please tell me the reason for this unexpected behaviour?My question here is to find the value of Count_22.Is there any problem with the code?
Thanks and regards,
Maddy
Your code is probably one of the worst pieces of C code i've ever seen (no offense, everybody has to learn sometime).
It has syntax errors (maybe copy/paste problem), logical problems, meaningless obfuscation, bad practices (globals), buffer overflow (atoi used on a char where there is no place to store the terminating zero byte), uninitialized values (Count_22), surprising naming convention (mixed CamelCase and underscore, variables and functions beginning with capital letter), infinite loop, no header and I forget some.
More, if you want anyone to help you debug this code, you should at list say what it is supposed to do...
To answer to the original question: why Count_22 is never incremented ?
Because Is_Milestone is always false (with or without #Jay change). Is_Milestone intend seems to be to compare the decimal value of the string "22" with the integer 21 (or 1, boolean result of 21 == 1) depending on the version).
It's logical because of Advance_String behavior. both because String has bad initial value (should probably be char String[3] = "00";) and because of the Value != 7 test. I guess what you wanted was comparing the digit with 7, but atoi works with a full string. Another minor change to achieve that Atoi_val = atoi(String+1); in the body of your loop. Then again you won't see much as the loop never stop and never print anything.
If it is a first attempt at an exercice given by some teacher (something like "programming a two digit counter in base 7" or similar). You should consider not using atoi at all and converting characters digit to value using something like:
digit_value = char_value - '0';
example:
char seven_as_char = '7';
int seven_as_int = seven_as_char - '0';
If you can explain what you are really trying to do, we may be able to show you some simple sample code, instead of the horror you are trying to debug.
EDIT
It is really more simple with original code...
After reading the Ada source, I can confirm it is indeed an Ascii based octal counter. The original code is allready of poor quality, and that explains part of the bad quality of the resulting C code.
A possible direct port could be as following (but still need a serious cleanup to look like native C code... and is quite dumb anyway as it prints a constant):
#include <stdio.h>
#include <stdlib.h>
void Advance_String(char * P1)
{
if((P1[1]-'0') != 7){
P1[1]++;
}
else{
P1[1] = '0';
P1[0]++ ;
}
}
int Is_Milestone(char * P1, int P2)
{
return (atoi(P1) > P2);
}
main()
{
int Count_11 = 0;
int Count_22 = 0;
int Count_33 = 0;
int Count_44 = 0;
char S[3] = "00";
int cont = 1;
while(cont)
{
if(Is_Milestone(S, 10)){
if(atoi(S) == 11){
Count_11 = Count_11 + 1;
}
if(Is_Milestone(S, 21)){
if(atoi(S) == 22){
Count_22 = Count_22 + 1;
}
if(Is_Milestone(S, 32)){
if(atoi(S) == 33){
Count_33 = Count_33 + 1;
}
if(Is_Milestone(S, 43)){
if(atoi(S) == 44){
Count_44 = Count_44 + 1;
}
if (atoi(S) == 77){
cont = 0;
}
}
}
}
}
Advance_String(S);
}
printf("result = %d\n", Count_11 + Count_22 + Count_33 + Count_44);
}
This statement
if(Is_Milestone(S,21==1) // Braces are not matching. If statement is not having the closing brace. Compilation error should be given.
should be
if(Is_Milestone(S,21)==1)
I guess.
Also, the code you have posted doesn't seem to be correct. It will surely give compilation errors. You have declared Count22, but are using Count_22.
Please check.

Resources