Fixed parsing telnet NAWS with either size of 255
[rlserver.git] / users.c
blob7a5dc31b05bcec032a6a43c95399947883a5c5e1
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <unistd.h>
6 #include "users.h"
8 #define USERS_FILE "./users"
11 static int check_user_name (const char *name)
13 int i;
16 if (!isalpha(name[i])) return 0;
18 for (i = 1; name[i] != 0; i++)
20 if (!isalnum(name[i])) return 0;
23 // minimal length
24 return i >= 3;
30 * str must be 0-terminated
31 * NB! content of str will be destroyed in the process
33 static int parse_user (user *usr, char *str)
35 char *s;
36 if ((s = strstr(str, ":")) == NULL) return 0;
37 *s = 0;
39 // id
40 usr->id = atoi(str);
42 str = s + 1;
43 if ((s = strstr(str, ":")) == NULL) return 0;
44 *s = 0;
46 // name
47 strncpy (usr->name, str, USER_NAME_LEN);
48 usr->name[USER_NAME_LEN - 1] = 0;
50 str = s + 1;
51 if ((s = strstr(str, ":")) == NULL) return 0;
52 *s = 0;
54 // password
55 strncpy (usr->pass, str, USER_PASS_LEN);
56 usr->name[USER_PASS_LEN - 1] = 0;
58 str = s + 1;
59 if ((s = strstr(str, "\n")) != NULL) *s = 0; // remove optional \n at the end
61 // email
62 strncpy (usr->email, str, USER_EMAIL_LEN);
63 usr->name[USER_EMAIL_LEN - 1] = 0;
65 return 1;
70 #define BUF_SZ 1024
73 * if user is not found usr will be filled with garbage
74 * and also if max_id is not NULL, it will contain max encountered user id
76 static int find_user (const char *name, user *usr, FILE *f, int *max_id)
78 int m = 0;
80 while (1)
82 char buf[BUF_SZ];
84 // end of file
85 if (fgets(buf, BUF_SZ, f) == NULL) break;
87 // skip comments and empty lines
88 if (buf[0] == '#' || buf[0] == 0) continue;
90 if (!parse_user(usr, buf))
92 continue;
95 // logins are case-insensitive
96 if (strcasecmp(name, usr->name) == 0) return usr->id;
98 // update max id
99 if (usr->id > m) m = usr->id;
102 if (max_id != NULL) *max_id = m;
103 return 0;
108 int add_user (user *usr, const char *name, const char *pass, const char *email)
110 int id;
111 FILE *f;
113 if (!check_user_name(name)) return -1;
115 f = fopen(USERS_FILE, "r+");
116 if (f == NULL) return -2;
118 // lock file to block access from other threads
119 if (lockf(fileno(f), F_LOCK, 0) != 0)
121 fclose (f);
122 return -3;
125 // user already exists
126 if (find_user(name, usr, f, &id))
128 fclose (f);
129 return -4;
132 id++;
133 usr->id = id;
135 strncpy (usr->name, name, USER_NAME_LEN);
136 usr->name[USER_NAME_LEN - 1] = 0;
138 strncpy (usr->pass, pass, USER_PASS_LEN);
139 usr->pass[USER_PASS_LEN - 1] = 0;
141 strncpy (usr->email, email, USER_EMAIL_LEN);
142 usr->email[USER_EMAIL_LEN - 1] = 0;
144 // add user record to the file
145 fseek (f, 0, SEEK_END);
146 fprintf (f, "%d:%s:%s:%s\n", usr->id, usr->name, usr->pass, usr->email);
148 fclose (f);
150 return id;
155 int user_login (user *usr, const char *name, const char *pass)
157 int id;
158 FILE *f;
161 f = fopen(USERS_FILE, "r+"); // r+ is needed for locking
162 if (f == NULL) return -2;
164 // lock file to block access from other threads
165 if (lockf(fileno(f), F_LOCK, 0) != 0)
167 fclose (f);
168 return -3;
171 id = find_user(name, usr, f, NULL);
172 fclose (f);
174 if (id <= 0) return -4;
176 if (strcmp(pass, usr->pass) != 0) return -5;
178 return id;