Solved

[C server] Login and blank spaces

Posted on 2008-06-19
15
255 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 7
15 Comments
 
LVL 45

Expert Comment

by:sunnycoder
ID: 21828064
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
ID: 21828286
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
ID: 21829819
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
Webinar: Aligning, Automating, Winning

Join Dan Russo, Senior Manager of Operations Intelligence, for an in-depth discussion on how Dealertrack, leading provider of integrated digital solutions for the automotive industry, transformed their DevOps processes to increase collaboration and move with greater velocity.

 
LVL 45

Expert Comment

by:sunnycoder
ID: 21829937
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
ID: 21829949
>> 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
ID: 21829980
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
ID: 21830062
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
 
LVL 45

Expert Comment

by:sunnycoder
ID: 21830614
>, 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
ID: 21837291
>>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
ID: 21838359
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
ID: 21838422
i debugged it by adding a printf...
it never calls verify_login, it crashes before...

0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 21839576
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
ID: 21839579
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
ID: 21841037
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
ID: 31656936
thanks!
Great Input!
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
How to install SVN Command Line Client? 5 109
Why is compiler in oracle server ? 9 100
forensics tools for file amendments/associations 2 105
Password manager for small company 3 48
I use more than 1 computer in my office for various reasons. Multiple keyboards and mice take up more than just extra space, they make working a little more complicated. Using one mouse and keyboard for all of my computers makes life easier. This co…
This guide will walk you through the essential considerations and tech stack for building scalable websites. Know how to grow your business the smart way!
The viewer will learn how to set up a document for the web and print and the recommended PPI for printing.
The viewer will learn how to successfully download and install the SARDU utility on Windows 7, without downloading adware.

730 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