Reputation: 1779
This is the file auth.txt (username password)
paolo 1234
luca 0000
marci 1000
And this is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void onexit(char *u, char *p, char *l, FILE *f, int flag);
int main(int argc, char *argv[]){
FILE *fp;
char *tmp, *tmp2, *user, *pass, *line;
printf("Inserire utente: ");
if(scanf("%ms", &user) == EOF){
perror("scanf");
return EXIT_FAILURE;
}
printf("Inserire password: ");
if(scanf("%ms", &pass) == EOF){
perror("scanf");
onexit(user, NULL, NULL, NULL, 1);
return EXIT_FAILURE;
}
size_t max_length = strlen(user) + strlen(pass) + 3;
line = malloc(max_length);
if(line == NULL){
perror("malloc");
onexit(user, pass, NULL, NULL, 2);
return EXIT_FAILURE;
}
fp = fopen("/home/pol/auth.txt", "r");
if(fp == NULL){
printf("Errore apertura file\n");
onexit(user, pass, line, NULL, 3);
return EXIT_FAILURE;
}
while(!feof(fp)){
if(fgets(line, max_length , fp) == NULL){
perror("fgets");
onexit(user, pass, line, fp, 4);
return EXIT_FAILURE;
}
tmp = strtok(line, " ");
if(tmp == NULL){
perror("strtok");
onexit(user, pass, line, fp, 4);
return EXIT_FAILURE;
}
tmp2 = strtok(NULL, "\n");
if(tmp2 == NULL){
perror("strtok");
onexit(user, pass, line, fp, 4);
return EXIT_FAILURE;
}
if((strcmp(tmp,user) == 0) && (strcmp(tmp2,pass) == 0)){
printf("USER: %s - PASS: %s\n", tmp, tmp2);
onexit(user, pass, line, fp, 4);
return EXIT_SUCCESS;
}
else{
continue;
}
}
printf("no such user or pwd into DB\n");
onexit(user, pass, line, fp, 4);
return EXIT_FAILURE;
}
void onexit(char *u, char *p, char *l, FILE *f, int flag){
if(flag == 1){
free(u);
}
if(flag == 2){
free(u);
free(p);
}
if(flag == 3){
free(u);
free(p);
free(l);
}
if(flag == 4){
free(u);
free(p);
free(l);
fclose(f);
}
}
EDIT: another problem!
if i want to test luca
with 0000
i got:
Inserire utente: luca
Inserire password: 0000
strtok: Success
and the program stop.
It works only with 1st and 3rd input but not with the 2nd!
why??
Upvotes: 1
Views: 1106
Reputation: 35924
It looks like your while
loop will only go through one iteration:
while(!feof(fp)){
// ...
if((strcmp(tmp,user) == 0) && (strcmp(tmp2,pass) == 0)){ // if match, exit
printf("USER: %s - PASS: %s\n", tmp, tmp2);
onexit(user, pass, line, fp, 4);
return EXIT_SUCCESS;
}
else{ // else exit
printf("no such user or pwd into DB\n");
onexit(user, pass, line, fp, 4);
return EXIT_FAILURE;
}
}
...which seems a little funny. Do you really want to exit if the first line you read doesn't match?
Edit:
Another problem: you need to allocate space for user
and pass
before you send them into scanf
:
char *user;
scanf("%ms", &user); // error
Instead of that, you could try something like:
char user[100];
scanf("%ms", &user); // now user actually has some space to store data
(In your version, scanf
will try to write data into the location that user
points to, but user
just points at a random location in memory, so who knows what will happen.)
Whoops, as @MvG pointed out, this is fine. I wasn't familiar with the "%ms" POSIX extension.
Edit 2:
Say you enter the username uu
and the password pp
. Because of this:
size_t max_length = strlen(user) + strlen(pass) + 3;
...you'll set max_length
to 2 + 2 + 3
, or 7
. fgets will read data until it encounters at most max_length-1
characters or a newline character. That means when you get inside your while
loop, you'll only try to read at most 7-1
or 6
characters per iteration, which doesn't seem right.
For example, if your password file contains:
paolo 1234
luca 0000
marci 1000
...then line
will get the following values:
"paolo "
(with a trailing space)"1234"
"luca 0"
"000"
"marci "
(again, with a trailing space)"1000"
Instead of basing max_length
on the current username and password that you've read in, make max_length
a large fixed value (like 100
).
Upvotes: 3
Reputation: 60908
Your error handler is inside the while loop. If the user isn't the first in the file, you abort immediately. Beter write it this way:
…
if((strcmp(tmp,user) == 0) && (strcmp(tmp2,pass) == 0)){
printf("USER: %s - PASS: %s\n", tmp, tmp2);
onexit(user, pass, line, fp, 4);
return EXIT_SUCCESS;
}
}
printf("no such user or pwd into DB\n");
onexit(user, pass, line, fp, 4);
return EXIT_FAILURE;
}
I can reproduce the strtok: Success
problem when there is an entry in the database without a space in between. This might even be an empty line at the end of the file, in cases where the loop proceeds this far. In that case, the first strtok will return the whole string, and the second strtok will return NULL, thus indicating that there are no more tokens. As this is no error message, the errno status is zero, corresponding to the “error message” Success
.
I guess in your case the problem lies in the different length of the records. You measure the length of your line read buffer by the length of the input, but some records are longer. In that case, you read part of a line and split that correctly, and at the next run you read the remainder of the line and end up with what appears like a line without a space, including the behaviour I described above.
Upvotes: 1