Solved

[C server] Login and blank spaces

Posted on 2008-06-19
15
243 Views
Last Modified: 2013-11-15
Hi to all!

I was wondering about the possibility of managing usernames which contain blank spaces.

I use read function to read the commands which the client sends to the server, something like what i posted below.

Each line ends with a "\r\n" sequence, so i try to delete it and to consider just what the client really writes.
The problem is that my code works fine if the username doesn't contain blank spaces, but if it is something like: "user name" my code doesn't work and it crashes.

It's like when you use scanf() and fgets()...

What can I do in order to consider also the blank spaces and continue also to not consider \r\n?
what's the better way in order to avoid security problems, too?

the server works in this way:

server: WHO?
client: HELOusername\r\n
server: PASS
client:password\r\n

but it has also to work fine in this case:


server: WHO?
client: HELOuser name\r\n
server: PASS
client:password\r\n


thanks a lot!

while( (n = read(fd, buffer, MAX_LINE)) > 0){

   buffer[n] = '\0';

   char *comando = buffer;

   

   lenght = strlen(comando);

    if(lenght == 0){

            exit(0);

            }

   while (comando) {

  char *next = strstr(comando, "\r\n");

  if (next) {

    *next = '\0';

    next += 2;

  }

      

   if ( strncmp(comando, "HELO", 4) == 0){  

    

   username = strtok((comando+4), "\r\n");

   if (strlen(username) > 16){

   Writeline(fd, alert, strlen(alert));

   }

   Writeline(fd, passw, strlen(passw));

   read(fd, password, MAX_LINE);  

   passwd = strtok(password, "\r\n");

 

   if (verify_login(username, passwd)){

   auth=1;

   Writeline(fd, good, strlen(good));

   } 

   else {

   auth=0;

   Writeline(fd, fail, strlen(fail));

   }

   

   }

Open in new window

0
Comment
Question by:roccogalati
  • 7
  • 7
15 Comments
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
I am not sure what Writeline function does. Also why do you need to strtok on "\r\n"? Would there be newlines in the middle of your string?
Check the following code ... It should do what you are seeking.
char buffer[32];

chat * temp;

char * username;

char password[17];

...

while (fgets (buffer, 32, file)) //if you are reading input from user, use stdin in place of file

//Also would you be processing these commands at a stretch?? seems unlikely - in which case you do not need a while loop here

{

   temp = strstr(buffer,"\r\n");

   *temp = '\0';
 

   if (strncmp(buffer, "HELO", 4) == 0) 

   {

        username = buffer+4;

        if (strlen(username)>16)

            //handle error

        //prompt for password

        fgets(password,17,stdin);

        temp = strstr(password, "\r\n"); //add error checking if (temp) etc.

        *temp = '\0';

        verify(username,password);

        //handle failure and success of verification

   }

}

Open in new window

0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
usual security issues - you would be accepting passwords in clear text being echoed on screen ... you need to either switch off the echo to the terminal or use a function like getpass(now obsolete)
0
 

Author Comment

by:roccogalati
Comment Utility
the code i posted is on my server, i use Writeline to send messages to the client, and read to read from the client.

The client sends HELOusername and the server has to store the username in a string, then it asks to the client for a password and then it compares the data...

The actual problem is that the username can't contains blank spaces, because if i write HELOuser name it doesn't work fine... if i use HELOusername it is OK...
this is my writeline:
 

ssize_t Writeline(int sockd, const void *vptr, size_t n) {

    size_t      nleft;

    ssize_t     nwritten;

    const char *buffer;
 

    buffer = vptr;

    nleft  = n;
 

    while ( nleft > 0 ) {

	if ( (nwritten = write(sockd, buffer, nleft)) <= 0 ) {

	    if ( errno == EINTR )

		nwritten = 0;

	    else

		return -1;

	}

	nleft  -= nwritten;

	buffer += nwritten;

    }
 

    return n;

}

Open in new window

0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
It would indeed help tremendously if you could provide some more details about the issue you are facing. Which line is causing what problem? Any error messages - error numbers ...



The code really looks fine except for the strtok which is probably not required

   
   username = strtok((comando+4), "\r\n");      --->> why this strtok ... You already replaced the first \r of "\r\n" ... Note that string of delimiters means any of these can act as a delimiter ... it does not mean this string as delimiter. In all probability you dont want this statement.


>while( (n = read(fd, buffer, MAX_LINE)) > 0){
Is this loop meant to read multiple commands? In case you intend this function to authenticate only then a loop is unneccessary.

  if (next) {
    *next = '\0';
    next += 2;
  }
     
Again this piece of code serves no purpose for you.
0
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
>> because if i write HELOuser name it doesn't work fine...

define "doesn't work fine". Where and how does it fail ?
0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
if (next) {
    *next = '\0';
    next += 2;
  }
     
Again this piece of code serves no purpose for you. --->> referring to next+=2 bit ... you dont use value of next again
0
 

Author Comment

by:roccogalati
Comment Utility
I try to explain better what i'd like to do..

i need to use a loop because i have to handle multiple commands...


At the moment it seems to work OK, it verifies correctly usernames with and without blank spaces...

but i'd like to ask you, if you think my code is correct for what i want to do... because it seems to work now, but i'd like to avoid possible mistakes...

What i need is to be able to read username and password and to store it in a string and passing them to the verify function.
But i have to delete the \r\n from each line, because i need just the correct username and password...

However, it seems to work OK now...

if ( strncmp(comando, "HELO", 4) == 0){

// if the string sended by client begin with HELO

    

username = strtok((comando+4), "\r\n");

//I read the username written 4 byte after HELO in the string and i don't need \r\n, //i have to delete them because i need just the username

 

   if (strlen(username) > 16){

   Writeline(fd, alert, strlen(alert));

   }

   Writeline(fd, passw, strlen(passw));

   read(fd, password, MAX_LINE);  

   passwd = strtok(password, "\r\n");

   //I try to read the password sended by the client and i store it in passwd, but i   //don't need extra chars, i need just the pass string, so i have to delete \r\n

 

   if (verify_login(username, passwd)){

   auth=1;

   Writeline(fd, good, strlen(good));

   } 

   else {

   auth=0;

   Writeline(fd, fail, strlen(fail));

   }

Open in new window

0
Complete VMware vSphere® ESX(i) & Hyper-V Backup

Capture your entire system, including the host, with patented disk imaging integrated with VMware VADP / Microsoft VSS and RCT. RTOs is as low as 15 seconds with Acronis Active Restore™. You can enjoy unlimited P2V/V2V migrations from any source (even from a different hypervisor)

 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
>, but i'd like to avoid possible mistakes...
Use defensive programming techniques ...
initialize all variables
check all return values
check for NULL before dereferencing
check all parameters for sanity
use safe functions which allow you to limit the memory you would be accessing e.g. strncpy instead of strcpy
http://en.wikipedia.org/wiki/Defensive_programming

>But i have to delete the \r\n from each line, because i need just the correct username and password...
Thats right .... whatever is in the input stream has to be read ... there are various ways of doing it but probably the most robust is the one you are using - fread()/fgets()/read().
Just one drawback ... what if input is malformed and there is no \r\n in say first 200 bytes ...

>passwd = strtok(password, "\r\n");
This would tokenize your string at either \r or \n ... this does NOT mean tokenize at sequence "\r\n" ... This statement is equivalent to
passwd = strtok(password, "\n\r");
Probably what you want is strstr as you were using before ... that would return NULL if the string is malformed (too long, incorrectly delimited)

char * temp = strstr (buffer, "\r\n");
if (!temp)
       //no delimiter ... handle malformed string
else
       *temp  = '\0'; // okay now effectively \r\n has been removed form the "string"

Cheers!
0
 

Author Comment

by:roccogalati
Comment Utility
>>char * temp = strstr (buffer, "\r\n");
>>if (!temp)
    >>   //no delimiter ... handle malformed string
>>else
    >>   *temp  = '\0'; // okay now effectively \r\n has been removed form the "string"

Thanks for your advices, sunnycoder!

I'll try and let you know in a while!

thanks a lot! u are great! ;)
0
 

Author Comment

by:roccogalati
Comment Utility
but if i'm using this at the begin of my code:

while( (n = read(fd, buffer, MAX_LINE)) > 0){
   buffer[n] = '\0';
   char *comando = buffer;
   
   lenght = strlen(comando);
    if(lenght ==0){
            exit(0);
            }
   while (comando) {
  char *next = strstr(comando, "\r\n");
  if (next) {
    *next = '\0';
    next += 2;
  }
   if ( lenght <= 500 ){  // strings long at max 500
 
   
   if ( strncmp(comando, "HELO", 4) == 0){  
   
   username = strtok((comando+4), "\r\n");
   if (strlen(username) > 16){
   Writeline(fd, alert, strlen(alert));
   }
   Writeline(fd, passw, strlen(passw));
   read(fd, password, MAX_LINE);  
   passwd = strtok(password, "\r\n");
 
   if (verify_login(username, passwd)){
   auth=1;
   Writeline(fd, good, strlen(good));
   }
   else {
   auth=0;
   Writeline(fd, fail, strlen(fail));
   }
   
   }


does it means that the string has already been purged by "\r\n" ?


because i'm having problems when i try to login, after having sending the password, the server close the connection, it seems that it crashes...

i try to understand what you wrote previously but i'm a little confused...  
0
 

Author Comment

by:roccogalati
Comment Utility
i debugged it by adding a printf...
it never calls verify_login, it crashes before...

0
 
LVL 45

Expert Comment

by:sunnycoder
Comment Utility
Indent your code properly ... that would make it more readable and also prevent brace mismatches.
while( (n = read(fd, buffer, MAX_LINE)) > 0)

{

   buffer[n] = '\0';

   char *comando = buffer;

   

   lenght = strlen(comando);

   if(lenght ==0)

   {

       exit(0);

   }
 

   while (comando) 

   {

        char *next = strstr(comando, "\r\n");

        if (next)

        {

            *next = '\0'; //Dont move next yet.

        }

        if ( lenght <= 500 )

        {   

             if ( strncmp(comando, "HELO", 4) == 0)

             {     

                 //username = strtok((comando+4), "\r\n"); If I remember correctly, username is a 16 char string right after HELO. Right now, comando contains HELOusername\0\nnextcommand\r\n ... So you do not want a strtok on \r\n

                 username = commando+4;

                 if (strlen(username) > 16)

                 {

                      Writeline(fd, alert, strlen(alert));

                 }

                 Writeline(fd, passw, strlen(passw));

                 read(fd, password, MAX_LINE);  

                 passwd = strtok(password, "\r\n");

 

                 if (verify_login(username, passwd))

                 {

                      auth=1;

                      Writeline(fd, good, strlen(good));

                 }

                 else 

                 {

                      auth=0;

                      Writeline(fd, fail, strlen(fail));

                 }  

           }     

     }

     if (next)

         commando = next+2; //move to next command here

}

Open in new window

0
 
LVL 45

Accepted Solution

by:
sunnycoder earned 500 total points
Comment Utility
okay ... I misplaced the loop advancement code
while( (n = read(fd, buffer, MAX_LINE)) > 0)

{

   buffer[n] = '\0';

   char *comando = buffer;

   

   lenght = strlen(comando);

   if(lenght ==0)

   {

       exit(0);

   }

 

   while (comando) 

   {

        char *next = strstr(comando, "\r\n");

        if (next)

        {

            *next = '\0'; //Dont move next yet.

        }

        if ( lenght <= 500 )

        {   

             if ( strncmp(comando, "HELO", 4) == 0)

             {     

                 //username = strtok((comando+4), "\r\n"); If I remember correctly, username is a 16 char string right after HELO. Right now, comando contains HELOusername\0\nnextcommand\r\n ... So you do not want a strtok on \r\n

                 username = commando+4;

                 if (strlen(username) > 16)

                 {

                      Writeline(fd, alert, strlen(alert));

                 }

                 Writeline(fd, passw, strlen(passw));

                 read(fd, password, MAX_LINE);  

                 passwd = strtok(password, "\r\n");

 

                 if (verify_login(username, passwd))

                 {

                      auth=1;

                      Writeline(fd, good, strlen(good));

                 }

                 else 

                 {

                      auth=0;

                      Writeline(fd, fail, strlen(fail));

                 }  

           }     

           if (next)

               comando = next+2; //move to next command here

           else

               comando = NULL; // could as well have used break here

      }

}

Open in new window

0
 

Author Comment

by:roccogalati
Comment Utility
Thanks a lot, i indented better my code and used your inputs, now it looks like better...

thanks, thanks a lot!
0
 

Author Closing Comment

by:roccogalati
Comment Utility
thanks!
Great Input!
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

Skype is a P2P (Peer to Peer) instant messaging and VOIP (Voice over IP) service – as well as a whole lot more.
In this article, you will read about the trends across the human resources departments for the upcoming year. Some of them include improving employee experience, adopting new technologies, using HR software to its full extent, and integrating artifi…
An overview on how to enroll an hourly employee into the employee database and how to give them access into the clock in terminal.
XMind Plus helps organize all details/aspects of any project from large to small in an orderly and concise manner. If you are working on a complex project, use this micro tutorial to show you how to make a basic flow chart. The software is free when…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now