Sockets – Socket FTP in C: authentication gets 530 “Please login with user and pass” with anonymous

cftpsockets

I'm trying to connect to a server to download an POS (Point of sale) application. For now, I'm trying to make work on the PC to adapt to the POS. (The POS doen't have a FTP API, just socket)

Trying to connect to ftp://ftp.inf.puc-rio.br/ (139.82.16.194). I also tried ftp.dca.fee.unicamp.br with the same result.

I'm using sys/socket.h. I'm getting this:

220 Bem Vindo ao Servidor do DI / PUC-Rio.

USER anonymous

Response: 331 Please specify the password.

PASS 123

Response: 530 Please login with USER and PASS

I tried another passowords like email, guest but no sucess.
In Filezilla I use the same values (IP, user, password 123 and port 21) and I get this:

USER anonymous

Response: 331 Please specify the password.

Comando: PASS ***

Response: 230 Login successful.

Trying to understand why the server don't accept the PASS command.

Here is my code:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <errno.h>

#define SERVER_PORT_ID 21
#define CLIENT_PORT_ID 8015
#define SERVER_HOST_ADDR "139.82.16.194"
/* ftp.dca.fee.unicamp.br */
//ftp://ftp.inf.puc-rio.br/
#define MAXSIZE 256    

main(int argc,char *argv[]){           

    int sockid, newsockid,i,getfile,ack,msg,msg_2,c,len;
    int no_writen,start_xfer, num_blks,num_last_blk;
    struct sockaddr_in my_addr, server_addr;
    FILE *fp;
    char in_buf[MAXSIZE], buffer[MAXSIZE];       


    if ((sockid = socket(AF_INET,SOCK_STREAM,0)) < 0)
    {
        printf("client: socket error : %d\n", errno); exit(0);
        
    }
    
    printf("client: binding my local socket\n");
    bzero((char *) &my_addr,sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    my_addr.sin_port = htons(CLIENT_PORT_ID);
    if (bind(sockid ,(struct sockaddr *) &my_addr,sizeof(my_addr)) < 0)
    {
        printf("client: bind error :%d\n", errno); exit(0);

    }

    setsockopt(sockid,SOL_SOCKET, SO_KEEPALIVE, 0, MAXSIZE);

    //Try to connect
    printf("client: starting connect\n");
    bzero((char *) &server_addr,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(SERVER_HOST_ADDR);
    server_addr.sin_port = htons(SERVER_PORT_ID);
    if (connect(sockid ,(struct sockaddr *) &server_addr,
    sizeof(server_addr)) < 0)
    {
        printf("client: connect error :%d\n", errno); exit(0);

    }

//Print the Welcome message
    do{
        memset((void*) buffer,0,MAXSIZE);
        if(read(sockid,buffer,MAXSIZE) < 0) 
        {
            printf("client: read error :%d\n", errno); exit(0);
        }       
        printf("%s \n", buffer);
    }while(strstr(buffer,"220 ") == NULL);

    printf("Mensagem Welcome recebida\n");

//Try to connect

    stpcpy(buffer,"USER anonymous\r\n");
    printf("%s", buffer);
    if(write(sockid,buffer,sizeof(buffer))< 0){
        printf("client: write error :%d\n", errno); exit(0);
    }
    if(read(sockid,buffer,MAXSIZE) < 0)   
    {
        printf("client: read error :%d\n", errno); exit(0);
    }
    printf("%s", buffer);

    memset((void*) buffer,0,MAXSIZE);
    stpcpy(buffer,"PASS 123\r\n");  
    printf("%s", buffer);
    if(write(sockid,buffer,sizeof(buffer))< 0){
        printf("client: write error :%d\n", errno); exit(0);
    }
    memset((void*) buffer,0,MAXSIZE);
    if(read(sockid,buffer,MAXSIZE) < 0) 
    {
        printf("client: read error :%d\n", errno); exit(0);
    }
    printf("%s \n", buffer);

    exit(0);
}

The code are not downloading anything. I'm trying to athenticate frist. Some includes and variables are not used because belongs to the FTP application's exemple that have the rest of code to download.

FTP Authentication

Thanks everyone!

Best Answer

The most central problem with the code is that the lengths given to write() come from sizeof. If you change those to calls to strlen(), the anonymous login works. Using sizeof for the length sends 256 bytes to the server.

At least the one ftp-server I tried this with (vsftpd), did not like the password otherwise. I did not check the RFC to see if it was the length or the zeros that made it clash. For development you might also want to install some ftpd software locally. I think it might be more prudent to experiment against servers you run yourself.

NIT: I dont know what system you are compiling that code on, but on a Linux/Posix system it would require some more includes. I added

#include <string.h> 
#include <stdlib.h>
#include <unistd.h>

I suggest you compile with either the clang compiler or use the flags -Wall -Werror -Wextra to gcc.

I also suggest using strerror() or similar instead of just printing the errno, when something fails.

Related Topic