Creating a login with C++

Discussion in 'Mac Programming' started by dq9, Mar 13, 2008.

  1. dq9
    macrumors newbie

    Joined:
    Mar 13, 2008
    Messages:
    26
    Location:
    Macintosh HD/Users/dq9
    #1
    Ok, so I am kinda new to C++, kinda not.
    I am trying to create a login for a command line utility C++ program. I followed the post here, and made a few modifications to the code.
    Here is my code:
    Code:
    // test.cpp : Defines the entry point for the console application.
    //
    
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cstdlib> // for exit(1);
    
    using namespace std;
    
    
    void Login();
    
    int main()
    {
    	Login();
    	return 0;
    }
    
    void Login()
    {
    	char login_un[50], login_pw[50], username[50], password[50];
    	int c;
    	ifstream uin("user.txt");
    	ifstream pin("pass.txt");
    	
    	cout<<"Main\n\n"
    		<<"(1) Login\n"
    		<<"(2) Quit\n";
    	cin>> c;
    	
    	
    	
    	if (c==1)
    	{
    		uin.getline(username, 50);
    		while (strcmp(login_un, username) !=0)
    		{
    			cout<<"Username: ";
    			cin.getline(login_un, 50);
    			if (strcmp(login_un, username) ==0) break;
    			else
    				cout<<"\nInvalid Username.\n";
    		}
    		
    		pin.getline(password, 50);
    		while (strcmp(login_pw, password) !=0)
    		{
    			cout<<"\nPassword: ";
    			cin.getline(login_pw, 50);
    			if (strcmp(login_pw, password) ==0) break;
    			else
    				cout<<"\nInvalid Password\n";
    		}
    		
    	}
    	
    	else if (c==2)
    	{
    		cout<<"Quitting\n";
    		exit(1);
    	}
    	return;
    }
    My user.txt is as follows:
    Code:
    admin
    dq9
    guest
    My pass.txt is as follows:
    Code:
    test
    pie
    -
    When I type in admin and test for the user and password, everything works fine. But when I try dq9 or guest with their passwords or even the admin password, the program says "Invalid Username." What can I do to fix this so I can login with dq9 or guest?
     
  2. macrumors newbie

    Joined:
    Mar 14, 2008
    Messages:
    21
    #2
    it has many problems

    This program is pretty weird in many respects, but to the answer the question,
    it does not work for any other name then admin:test because the next lines from *.txt files are never read, only one line is read from each file.
     
  3. macrumors member

    Joined:
    Apr 21, 2007
    Messages:
    46
    #3
    C++ Code..

    Okay, first off...does it give you any errors?

    Second off..why don't you just use one file? Make the format like this..

    USERNAME PASSWORD
    USERNAME2 PASSWORD2
    USERNAME3 PASSWORD3

    then, do a loop to the end of the file
    (remember fin is the name of my ifstream class..)
    (be sure to include <string>)

    string username[50], password[50]; //Assuming you wont have more than 50 usernames/passwords stored..

    int i = 0;
    while(!fin.eof())
    {
    fin >> username;
    fin >> password;
    i++;
    }

    Then you can do..the comparison...
    int INDEX = //whatever the username/password combo you need to grab via the array
    if(username[INDEX] == typed_username && password[INDEX] == typed_password)
    {
    cout << "Successful Login..";
    }

    else
    {
    cout << "Error...";
    }


    If you need more help, don't hesitate to ask..but it seems like your biggest problems are #1: The file organization and #2: What usernames/passwords in the .txt file to compare with the typed information.

    - Zac
     
  4. dq9
    macrumors newbie

    Joined:
    Mar 13, 2008
    Messages:
    26
    Location:
    Macintosh HD/Users/dq9
    #4
    I don't understand the part where you added in INDEX. Can you show me an example code of how I would use that?

    And thanks for the help so far.
     
  5. macrumors member

    Joined:
    Apr 21, 2007
    Messages:
    46
    #5
    Sorry for the delay..

    Okay, when I say Index..I mean like this:

    In an array..you have for example this...

    Array[0]
    Array[1]
    Array[2]

    Right?

    The part in between the [ ]'s is considered the "index"

    So when I put index..its assuming you will have figured out what will be in between the index..

    for example if I did a for loop like this


    for(i = 1; i<5; i++)
    {
    cout << "array[" << i << "]" << endl;
    }

    You would get something like this:
    array[1]
    array[2]
    array[3]
    array[4]

    in that case..the "i" was the index.

    Does that make sense?

    I'd be more than happy to help out more..just message me on aim..

    World War Zac


    - Zac
     
  6. dq9
    macrumors newbie

    Joined:
    Mar 13, 2008
    Messages:
    26
    Location:
    Macintosh HD/Users/dq9
    #6
    Ok I understand a little more now. I still don't understand what you mean by username/password combo.
     
  7. dq9
    macrumors newbie

    Joined:
    Mar 13, 2008
    Messages:
    26
    Location:
    Macintosh HD/Users/dq9
    #7
    sorry for doublepost

    How do I change the INDEX with each different username so I'm not searching the same index every time?
     
  8. macrumors G4

    Joined:
    Jan 5, 2006
    Messages:
    11,012
    Location:
    Redondo Beach, California
    #8
    This is really not the best way to do this. First off it is trivally simple to crack this even after you get it to work. The passwords are inside you executable file for anyone to find. If this is a class asignment then OK but if this is a real world application you need a better scheeme.

    As luck would have it this problem was solved 30 or years ago and you don't have to re-invent the wheel.

    use the "getpass" funtion to read the password. It will turn off character echo.

    Next use the function "crypt" on what the user typed. and zero out the cleartext passwd with "memset"

    next make a call to "getpwent" to get the user's encrypted password. Compare with above.

    There are man pages for all of the above functions and the above method is portable and works on all UNIX-like systems, Mac OS X, Solaris and so on. C++ is pretty easy to learn but what takes a longer time is the environment and all the libraries. I've been at this from back when UNIX was new and I don't know a tenth of it.
     
  9. dq9
    macrumors newbie

    Joined:
    Mar 13, 2008
    Messages:
    26
    Location:
    Macintosh HD/Users/dq9
    #9
    Do you know of any tutorials on how to use those functions?

    I eventually want to port this over to Windows, that's why I'm coding things the way I am, will those functions work in Windows as well?
     
  10. macrumors member

    Joined:
    Apr 21, 2007
    Messages:
    46
    #10
    encrypting.

    He's right...it's not the best way to do things.

    As far as the encryption..im sure its similar to the way I do it in PHP.

    I THINK this is how it would work.

    Lets say your password is: ABC and you want to encrypt it.

    string password;

    crypt(password);
    //May look something crazy (im making this up) (*#*(*@&*E@DM*DUM@(*U@ = encrypted password

    Then..to check

    cin >> pass;


    Notice how when I CHECK the password, I encrypt the password they type in. The STORED password that you are comparing the TYPED password to is already encrypted...so you just need to encrypt the password that user types in and compare that encrypted password with the already encrypted password that you have stored for comparison.


    Does that make sense?

    For example:
    if(password == crypt(pass))
    {
    //valid password
    }

    - Zac
     
  11. dq9
    macrumors newbie

    Joined:
    Mar 13, 2008
    Messages:
    26
    Location:
    Macintosh HD/Users/dq9
    #11
    I probably should have added earlier, I'm a bit slow (drugs, long story, I'm clean now)

    None of that made any sense at all!
    The method we had going earlier made a bit of sense. Can some one expand on that?
     
  12. macrumors member

    Joined:
    Apr 21, 2007
    Messages:
    46
    #12
    Re-explination

    Okay,

    Example: - This is the database you stored the usernames and passwords in
    ------------------------------------------------------------------------------------------------------------------------------
    U-name:
    Zac
    John

    Pass:
    (@*R)(@*D()@UF)(*@(*@ (This is Zac's encrypted password. His real UNENCRYPTED pass is lets say... 'ZacsPass')
    AJ*()*)(R*(U@OIJFIL@F*L (This is Encrypted word for 'Johny123' HIS real UNENCRYPTED pass is lets say ... 'Johny123')
    ------------------------------------------------------------------------------------------------------------------------------
    I input the username and password from the .txt file

    Example:

    fin >> fromFile_Username
    fin >> fromFile_Password

    Lets say I'm Zac..and I want to login.

    It asks for my username...I type in 'Zac'
    It asks for my password...I type 'ZacsPass' (this would be cin>>password)

    So what now? Well, fromFile_Password is the password stored in the .txt file..which is encrypted...it is as I wrote: (@*R)(@*D()@UF)(*@(*@

    But the password 'Zac' typed into the C++ program was 'ZacsPass'...thats not encrypted.

    All you need to do ..is encrypt 'ZacsPass' and compare it with the password stored in the .txt file:

    Example being.. (remember...the variable 'password' below was set to be 'ZacsPass' because thats what he typed in)
    if(fromFile_Password == crypt(password))
    {
    //return true
    }
    else
    {
    //Invalid
    }


    Does that help?
     
  13. dq9
    macrumors newbie

    Joined:
    Mar 13, 2008
    Messages:
    26
    Location:
    Macintosh HD/Users/dq9
    #13
    Thank you for all your help so far.

    I just have one last question about the password in the .txt file. When I encrypt it, is there a process I must follow or can I just type in random characters?

    Ok sorry for doublepost

    Forget all this encryption stuff. It's way over my head.

    Can you guys please just explain how to do this with text from a regular text file. Or write a sample source code for me to look at.
     
  14. macrumors member

    Joined:
    Apr 21, 2007
    Messages:
    46
    #14
    When I have time, Ill make u a video C++ tutorial.

    - Zac
     
  15. dq9
    macrumors newbie

    Joined:
    Mar 13, 2008
    Messages:
    26
    Location:
    Macintosh HD/Users/dq9
    #15
    You don't have to go to that much trouble, but if you do thank you very much.
     
  16. macrumors 6502

    jeznav

    Joined:
    Aug 10, 2007
    Messages:
    452
    Location:
    Eh?
    #16
    Lol...@ everyone trying to make it difficult

    All he wanted was to compare two strings from a text file(s) if it matches or not.

    Anyways, the part in your program what made it not work because you did not have any sort of indexing to indicate WHERE it should read next.

    What you should do is:

    1. When the user enters a the username, have a WHILE LOOP until EOL and check if the username entered MATCHES the line read in user.txt. Also, you must create a variable that will increment by 1 every time the loop passes. The variable acts as a counter to indicate WHERE the username in the file was read. You must place it inside the while loop at the very end.

    Conditions: IF the the username entered does not match ANY of the strings in the user.txt then you can print some error message not having a valid username.

    2. So after that loop has finished and that we found a valid username, (the important thing that we have is a variable which is the index for the pass.txt) you need to use that variable to move down the list in the pass.txt

    Do this by creating a FOR loop with that variable and in that for loop you read line.

    Example: Suppose I typed in guest as my username. The while loop iterated the 3rd time through user.txt and found it. It also gave a number value of 2 in my counter variable (remember that the variable started from 0, that means value of 0 = 1st line , 1 = 2nd line , 2 = 3rd line, etc,). As it goes to the password checker, the for loop has read a line in pass.txt 3 times which give you the string value of -

    Now you can do string comparison on the password entered and what it has read from the file..

    Conditions: IF no matching password where on the list then again...put any error message you like indicating wrong password.

    Hope that helps!!!

    -jez
     
  17. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Messages:
    3,172
    Location:
    Dallas, TX
    #17
    As I've been reading more of these forums lately, I figured I may as well brush up on some C++. Excuse any C-isms, I tried to keep it stream and string oriented, etc.

    Code:
    #include <iostream>
    using std::cout;
    using std::cin;
    using std::endl;
    #include <fstream>
    using std::ifstream;
    #include <string>
    using std::string;
    
    string readString(ifstream&);
    
    int main(int argc, char *argv[]) {
      char user[80];
      char pass[80];
      string line_in;
      string::size_type pos;
      ifstream fp_in;
      int count = 0;
      string user_pass[100][2];
    
      fp_in.open("users.txt"); //Open user file
      if(fp_in == NULL) {
        cout << "Could not open user file, exiting." << endl;
        return -1;
      }
      while(!fp_in.eof()) { //While there is something to read
        line_in=readString(fp_in);  //Read a line from the file
        if(line_in.length() > 0) { //If the line is non-empty
          pos = line_in.find("\t",0); //Find the tab deliminter
          if( pos != string::npos) { //If a tab is found..
            user_pass[count][0] = line_in.substr(0,pos); //Get username
            user_pass[count][1] = line_in.substr(pos+1); //Get password
            //cout << "User: " << user_pass[count][0] << " Pass: " << user_pass[count][1] << endl;
            count++;
          }
        }
      }
      fp_in.close(); //Done with the user file
      if(!count > 0) {
        cout << "Userlist is empty, exiting" << endl;
        return -2;
      }
      int logged_in=0;
      while(!logged_in) { //Force user to login. Give a quit option if you'd like
        cout << "Enter user name: ";
        cin >> user;
        cout << "Enter password: ";
        cin >> pass;
        int found = 0;
        for(int x=0;x<count && !found;x++) { //For each user/password pair..
          if(user_pass[x][0].compare(user) == 0) { //Matched the username
            found = 1;
            if(user_pass[x][1].compare(pass) == 0) { //Matched user and pass
              found = 1;
              logged_in = 1;
            } else {
              cout << "Invalid password!" << endl;
            }
          }
        }
        if(!found) {
          cout << "Invalid username!" << endl;
        }
      }
      //Once we're done with that loop, they logged in successfully.
      cout << "Logged in successfully!" << endl;
      return 0; 
    }
    
    string readString(ifstream& reader) {
      char buffer[256];
      reader.getline(buffer,256);
      string str1 = buffer;
      return str1;
    }
    
    
    I think it's better to just buffer up the users and passwords rather than rewinding the file each time to check if what was entered is in the file.

    Hope this helps. There's no encryption, etc. I thought i'd keep it simple. I probably didn't catch all of the edge cases, but it should be enough to give you some ideas, get you started, etc.

    -Lee
     
  18. dq9
    macrumors newbie

    Joined:
    Mar 13, 2008
    Messages:
    26
    Location:
    Macintosh HD/Users/dq9
    #18
    Thank you both! I still have yet to fix my problems, damn college taking up all my time, but I will definitely take pointers (get it? Ok bad joke.) from both your posts. Thanks for the help and I'll let you guys know how I make out.
     
  19. macrumors newbie

    Joined:
    Apr 3, 2008
    Messages:
    4
    #19
    can u please make it dynamic?

    Thanks Lee. I also was struggling with username/password codes until I found out your code. It's working perfectly if someone only wants to deal with predefined usernames and passwords.

    Is there any possibility to allow the user to change his assigned username or password (I mean personalize it)? In this case the code should be able to save both new username and password entries to the file users.txt at the position where was located the previous pair.

    Hope you can help out with this by some other code posted.
     
  20. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Messages:
    3,172
    Location:
    Dallas, TX
    #20
    I would handle the possible changing of passwords the same way.

    Read up the whole file and store all of the usernames and passwords.

    If a user changes their password, you change it in memory, then write a routine that re-writes the whole file. You could certainly trouble yourself with getting the "right" line, but that's a lot of work for not a lot of payoff. You can apply this same method to adding or removing users as well. Read up the current file into memory, if a user is deleted you just remove them from the list in memory and write back. If a user is added, you just append to the list and write it out. The write routine would be the same for all of them.

    If there is any possibility that more than one user is accessing the "system" at a time, that changes things dramatically. You then need to start with file locking, etc.

    I know *I* can write that code, but the reason you're here is so you can learn. Get started and if you need help, post the code and what problem you're having. I am hoping this is a learning exercise for you, and not something that will be used seriously. If so, then file locking, encryption, etc. all start getting involved, and that really complicates an otherwise straight-forward way to learn basic programming and I/O.

    -Lee
     
  21. macrumors newbie

    Joined:
    Apr 3, 2008
    Messages:
    4
    #21
    updating int count

    Thanks again Lee. Don't worry, this is a learning exercise. I'm busy writing routines for password/username changing and file rewriting. I'm having a problem with variable updating between two functions.

    In fact, in order to use your code efficiently, I divided it into smaller routines: OpenandReadFile(), Authenticate(), then created new routines: ChangeUsername(), ChangePassword() and RewriteFile().

    Before a user can change his username/password, he has to enter first the current username/password. So the Authenticate() routine has to be called before he can be granted the possibility to change anything.

    I'm using the variable count in the OpenandReadFile() routine and I need its updated value in the Authenticate routine. So I declared it globally. But I'm not getting the updated value when Authenticate() is called so the condition for the for loop is jeopardized. On the other hand I can't combine the OpenandReadFile() and the Authenticate() routines because I only need the Authenticate() routine when changing username/password.

    Do you understand something to my problem? If so, could you help? Sorry I'm sort of newbie to C/C++.

    Elie
     
  22. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Messages:
    3,172
    Location:
    Dallas, TX
    #22
    In a case like this I do not see the need for a global variable. In C++ you can pass by reference, or use C-style pointers to pass things to be modified into a function. You should be able to declare count in main, then pass it by reference or its pointer to OpenAndReadFile, which would update this value, then you can pass it to Authenticate.

    I don't know if you're taking a course, learning from a book, etc. so I don't know if pass by reference or pointer manipulation would come first in your studies. Chances are pass by reference, as it's considered easier, but the result is the same.

    -Lee

    P.S. You could avoid worrying about pass by reference or pointers by having OpenAndReadFile return an int which is the count. That way you could just assign the function's result to a variable in main, then pass that to Authenticate.
     
  23. macrumors newbie

    Joined:
    Apr 3, 2008
    Messages:
    4
    #23
    I got it - but have another question

    I got it thanks to Lee. You gave me the opportunity to learn about passing by reference. I passed "count" by reference to my OpenAndReadFile() routine then passed it to Authenticate. It worked perfectly. I'm even using the updated value of "count" in my RewriteFile() routine.

    Now I'm having a problem with the RewriteFile() routine. After the file has been rewritten, the authentication is no more successful. I'm getting an "Incorrect password" message for all users even the ones whose password hasn't been changed. But when I check the file "users.txt" it has been modified correctly and the new information (password) is at the right position. I don't know if there is a mess up with the tab delimiter or line ending in my code below.

    Note: When I rewrite the file "users.txt" manually, using notepad, and modify password or username, the authentication succeeds. Anyone knows the mistake in my code? Here is the code:

    void RewriteFile()
    {

    int row, col;

    ofstream myfile;
    myfile.open ("users.txt");
    if (myfile.is_open())
    {
    for (row=0; row<count; row++)
    {
    for (col=0; col<2; col++)
    myfile<<user_pass[row][col]<<"\t";
    myfile<<endl;
    }

    myfile.close();
    }
    else cout << "Unable to open file\n";

    }


    P.S. The RewriteFile() routine is called only after the change has been made in the user_pass[][] array.
     
  24. macrumors newbie

    Joined:
    Apr 3, 2008
    Messages:
    4
    #24
    Forget it

    Just forget it. I saw my mistake in the code. I solved it with an if statement. I'm cleared now. In fact I was printing two tab delimiters per line, one after the username and another after the password. So the second tab was creating a mismatch in the password.

    This code is now working:

    void RewriteFile()
    {

    int row, col;

    ofstream myfile;
    myfile.open ("users.txt");
    if (myfile.is_open())
    {
    for (row=0; row<count; row++)
    {
    for (col=0; col<2; col++)
    {
    myfile<<user_pass[row][col];
    if(col==0) myfile<<"\t";
    }
    myfile<<endl;
    }

    myfile.close();
    }
    else cout << "Unable to open file\n";

    }
     
  25. macrumors newbie

    Joined:
    Jan 22, 2011
    Messages:
    1
    #25
    undefined reference

    Hi Lee,

    I tried your code to learn but I received this debugging error :

    undefined reference to `line_in(std::basic_ifstream<char, std::char_traits<char> >&)'

    pointing to this statement : line_in=readString(fp_in);

    my data file looks like this:

    username password
    username password
    username password

    May I know what is wrong with this?

    thank you.
     

Share This Page