LINUX.ORG.RU

Авторизация в чате

 , ,


0

1

Написал какое-то подобие чата(клиент-сервер). И остался один вопрос. Имеется возможность задавать имена клиентам

Но проблема в том, что два клинта могут взять одинаковые имена, а это не очень хорошо. Как сделать простенькую авторизацию без внешних файлов с логинами/паролями?

 scanf("%s",name);
 strcpy(me.name, name);
...
char temp[NAMELEN];
printf("Enter name: ");
scanf("%s",temp);
...
sendtouser(&me, temp, message)


Последнее исправление: timas-cs (всего исправлений: 2)

Ответ на: комментарий от timas-cs

Ну дык «сервер» как по вашему переводится? Это то, что должно обхаживать клиентов, в том числе устранять бардак от пакостящих клиентов в угоду хорошим клиентам. Пусть сервер проверяет кто у него уже есть и просит поменять ник. Если вам хочется чтобы на C это вам показали, то увольте, ваш код настолько ужасен, что никакого желания его дополнять нет.

vodz ★★★★★
()
Ответ на: комментарий от crutch_master

Криптографический ключ + асинхронное шифрование.

И 100$/year для сертификата, чего уж мелочиться. :)

vodz ★★★★★
()
Ответ на: комментарий от vodz

Ни в коем случае. Это я привел отрывки того, как задается имя клиента и имя пользователя, которому адресуется сообщение. Я бы и сам написал, только пока не знаю как.

timas-cs
() автор топика

Можешь хранить в оперативной памяти какую-нибудь хэшмапу/список со связками занятых ников.

Чем хранение во внешнем файле не устроило?

Берешь струтуру(из ника, хэша от пароля и других служебных полей, которые тебе пригодятся) и плоско ее сохраняешь в файл, для ускорения процесса работы можешь держать закешированную копию в виде того же списка.

nihirash ★★★
()
Ответ на: комментарий от nihirash

Чем хранение во внешнем файле не устроило?

А вы уверены, что вопрос в хранении? Мне так кажется, что вопрос скорее всего как не спрашивая пароль сохранять за пользователем его ник. Ну так это невозможно, в IRC это решалось вначале либо канальным роботом либо расширением протокола IRC, который при попытке взять зарегистрированный ник начинает с тебя требовать пароль-подтверждения, что это вы.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Зачем? Сам передаешь своё имя и открытый ключ. На другой стороне его записывают как v.pupkin (F34AC3). Препод будет рад, я думаю.

crutch_master ★★★★★
()
Ответ на: комментарий от vodz

Мне так кажется, что вопрос скорее всего как не спрашивая пароль сохранять за пользователем его ник.

Есть мегапростой вариант - первая авторизация от какого-либо ника является его регистрацией.

nihirash ★★★
()
Ответ на: комментарий от nihirash

Есть мегапростой вариант - первая авторизация от какого-либо ника является его регистрацией.

Ну в IRC регистрация была на основе IP+ident. Теперь, когда в Инете привалили домохозяйки, ident дружно похерели, а у IPv4 сплошной NAT. Так что вы понимаете под «первая авторизация»?

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)

Никогда в жизни не пиши

scanf("%s",name);
Пиши так (если name имеет 256 байт)
scanf("%255s",name);
Иначе получишь переполнение буфера.

Так же никогда не пиши

 
strcpy(me.name, name);
Пиши
strncpy (me.name, name, me_name_length);
потому что опять же получишь переполнение буфера...

fsb4000 ★★★★★
()
Ответ на: комментарий от timas-cs

Когда клиент подключился, пусть сервер где нибудь у себя там сделает пометку об этом. Когда отключился, пусть сервер изменит пометку или удалит.

u0atgKIRznY5
()
Ответ на: комментарий от u0atgKIRznY5

решил для начала сделать для 2 клиентов: user_1 и user_2

в кленте задаю флаг, но что делать в сервере?

struct USER {
        int sockfd; 
        char name[NAMELEN];
	int flag;
};
struct USER me;

printf("================\n");
printf("Enter your login\n");
printf("================\n");
scanf("%s",instruction);
if((strcmp(instruction,user_1)==0)){flag=1;}
else if((strcmp(instruction,user_2)==0)){flag=2;}
else{printf("You are not a member, goodbye\n");break;}	
printf("FLAG=%d\n",flag);
strcpy(heap.name, instruction);
setname(&me);
me.flag=flag;
login(&me);

...

void login(struct USER *me) {
    int recvd;
    if(isconnected) {
        fprintf(stderr, "You are already connected to server at %s:%d\n", SERVERIP, SERVERPORT);
        return;
    }
    sockfd = connect_with_server();
    if(sockfd >= 0) {
        isconnected = 1;
        me->sockfd = sockfd;
        if(strcmp(me->name, "Anonymous")) setname(me);
        printf("Logged in as %s\n", me->name);
        printf("Receiver started [%d]...\n", sockfd);
        struct THREADINFO threadinfo;
        pthread_create(&threadinfo.thread_ID, NULL, receiver, (void *)&threadinfo);
 
    }
    else {
        fprintf(stderr, "Connection rejected...\n");
    }
}


///////SERVER

#define IP "127.0.0.1"
#define PORT 8080
#define BACKLOG 10
#define CLIENTS 10
 
#define BUFFSIZE 1024
#define NAMELEN 32
#define OPTLEN 16

struct HEAP {
    char instruction[OPTLEN]; // instruction
    char name[NAMELEN]; // client's name
    char buff[BUFFSIZE]; // payload
    int n; //flag
};
 
struct THREADINFO {
    pthread_t thread_ID; // thread's pointer
    int sockfd; // socket file descriptor
    char name[NAMELEN]; // client's name
};
 
struct LLNODE {
    struct THREADINFO threadinfo;
    struct LLNODE *next;
};
 
struct LLIST {
    struct LLNODE *head, *tail;
    int size;
};
 
int compare(struct THREADINFO *a, struct THREADINFO *b) {
    return a->sockfd - b->sockfd;
}
 
void list_init(struct LLIST *ll) {
    ll->head = ll->tail = NULL;
    ll->size = 0;
}
 
int list_insert(struct LLIST *ll, struct THREADINFO *thr_info) {
   ...
}
 
int list_delete(struct LLIST *ll, struct THREADINFO *thr_info) {...
}
 
void list_dump(struct LLIST *ll) {
  ...
}
 
int sockfd, newfd;
struct THREADINFO thread_info[CLIENTS];
struct LLIST client_list;
pthread_mutex_t clientlist_mutex;
 
void *io_handler(void *param);
void *client_handler(void *fd);
 
int main(int argc, char **argv) {
    int err_ret, sin_size;
    struct sockaddr_in serv_addr, client_addr;
    pthread_t interrupt;
 
    /* initialize linked list */
    list_init(&client_list);
 
    /* initiate mutex */
    pthread_mutex_init(&clientlist_mutex, NULL);
 
    /* open a socket */
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        err_ret = errno;
        fprintf(stderr, "socket() failed...\n");
        return err_ret;
    }
 
    /* set initial values */
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr.s_addr = inet_addr(IP);
    memset(&(serv_addr.sin_zero), 0, 8);
 
    /* bind address with socket */
    if(bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
        err_ret = errno;
        fprintf(stderr, "bind() failed...\n");
        return err_ret;
    }
 
    /* start listening for connection */
    if(listen(sockfd, BACKLOG) == -1) {
        err_ret = errno;
        fprintf(stderr, "listen() failed...\n");
        return err_ret;
    }
 
    /* initiate interrupt handler for IO controlling */
    printf("Starting admin interface...\n");
    if(pthread_create(&interrupt, NULL, io_handler, NULL) != 0) {
        err_ret = errno;
        fprintf(stderr, "pthread_create() failed...\n");
        return err_ret;
    }
 
    /* keep accepting connections */
    printf("Starting socket listener...\n");
    while(1) {
        sin_size = sizeof(struct sockaddr_in);
        if((newfd = accept(sockfd, (struct sockaddr *)&client_addr, (socklen_t*)&sin_size)) == -1) {
            err_ret = errno;
            fprintf(stderr, "accept() failed...\n");
            return err_ret;
        }
        else {
            if(client_list.size == CLIENTS) {
                fprintf(stderr, "Connection full, request rejected...\n");
                continue;
            }
            printf("Connection requested received...\n");
            struct THREADINFO threadinfo;
            threadinfo.sockfd = newfd;
            strcpy(threadinfo.name, "Anonymous");
            pthread_mutex_lock(&clientlist_mutex);
            list_insert(&client_list, &threadinfo);
            pthread_mutex_unlock(&clientlist_mutex);
            pthread_create(&threadinfo.thread_ID, NULL, client_handler, (void *)&threadinfo);
        }
    }
 
    return 0;
}
 
void *io_handler(void *param) {
...
}
 
void *client_handler(void *fd) {
...
}

timas-cs
() автор топика
Ответ на: комментарий от timas-cs

Делай на сервере флаг. Введенный ник клиента пусть сервер добавляет в список, и пусть в этом списке будет флаг активности клиента. Когда клиент вводит ник, пусть сервер проверяет список ников, и если есть одинаковый, пусть предлагает ввести заного.

u0atgKIRznY5
()
Ответ на: комментарий от vodz

И что он неправильно сказал? За strcpy, sscanf и подобные небезопасные говнофункции надо руки отрывать!

anonymous
()
Ответ на: комментарий от anonymous

За strcpy и подобные небезопасные говнофункции надо руки отрывать!

Попробую зайти с удочки. А вам не приходило в голову, почему strncpy юзается редко? Подсказка: не потому что все идиоты и безопасностью пренебрегают.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Да, верно. Немного забыл добавить

// char name[me_name_length+1]; //me_name_length максимальная длина, +1 для завершающего '\0' 
strncpy (me.name, name, me_name_length);
me.name[me_name_length] = '\0';
Раз уж добавляю, то ещё один совет от капитана очевидности, те значения которые возвращают функции, нужно проверять, чтобы быть уверенным, что эти функции выполнились правильно...

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Немного забыл добавить

Причём me_name_length это sizeof(me.name) - 1 и то, если это не указатель. А теперь внимание вопрос. А если me_name_length > sizeof(name) ? Получится тот же самый strcpy, только медленнее. А пользователя не надо предупреждать, что имя обрежется? А если вы таки реально парсите ввод, то там наверняка вы толи пробел, толи \n толи вообще какой '@' зарежете на '\0' и потому никакого lenght не будет, а будет указатель, потому правильнее всего будет предупредить, что длинное, и потом вообще сделать memcpy, а то и strdup. Потому удел у strncpy только у странных интерфейсов, типа инициализация if_name для bind(), когда можно и без '\0', но с '\0' когда меньше IFNAMSIZ (sic!)

vodz ★★★★★
()

хранить на сервере пару ник + uuid, клиент при подключении получает от сервера uuid и сохраняет его у себя, при новом подключении от с ником должен отправить сохранённый uuid если кто то другой будет подключатся с тем же ником ему бедет отказано так как его uuid не совпадёт с той парой что на сервере лежит. uuid можешь брать из /proc/sys/kernel/random/uuid

Deleted
()
Ответ на: комментарий от LamerOk

И где я могу увидеть бенчмарки?

Понятия не имею где, у меня просто есть чувство логики: если заменить функцию на такую же, но с дополнительным условием, то она будет работать либо медленнее, либо она первоначально была написана плохо. Соотношение использования этих функций эту логику подтверждает. И если вы думаете, что начинающий ради повышения безопасности тупо заменит и получит поожительный эффект, то у меня для вас плохие новости. В качестве доказательства вот тут уже проскакивало.

vodz ★★★★★
()
Ответ на: комментарий от LamerOk

У вас то? Ну наверное, с таким то ником...

vodz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.