-
Notifications
You must be signed in to change notification settings - Fork 39
/
myftpsrv_skel.c
237 lines (180 loc) · 5.43 KB
/
myftpsrv_skel.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
#include <unistd.h>
#include <err.h>
#include <netinet/in.h>
#define BUFSIZE 512
#define CMDSIZE 4
#define PARSIZE 100
#define MSG_220 "220 srvFtp version 1.0\r\n"
#define MSG_331 "331 Password required for %s\r\n"
#define MSG_230 "230 User %s logged in\r\n"
#define MSG_530 "530 Login incorrect\r\n"
#define MSG_221 "221 Goodbye\r\n"
#define MSG_550 "550 %s: no such file or directory\r\n"
#define MSG_299 "299 File %s size %ld bytes\r\n"
#define MSG_226 "226 Transfer complete\r\n"
/**
* function: receive the commands from the client
* sd: socket descriptor
* operation: \0 if you want to know the operation received
* OP if you want to check an especific operation
* ex: recv_cmd(sd, "USER", param)
* param: parameters for the operation involve
* return: only usefull if you want to check an operation
* ex: for login you need the seq USER PASS
* you can check if you receive first USER
* and then check if you receive PASS
**/
bool recv_cmd(int sd, char *operation, char *param) {
char buffer[BUFSIZE], *token;
int recv_s;
// receive the command in the buffer and check for errors
// expunge the terminator characters from the buffer
buffer[strcspn(buffer, "\r\n")] = 0;
// complex parsing of the buffer
// extract command receive in operation if not set \0
// extract parameters of the operation in param if it needed
token = strtok(buffer, " ");
if (token == NULL || strlen(token) < 4) {
warn("not valid ftp command");
return false;
} else {
if (operation[0] == '\0') strcpy(operation, token);
if (strcmp(operation, token)) {
warn("abnormal client flow: did not send %s command", operation);
return false;
}
token = strtok(NULL, " ");
if (token != NULL) strcpy(param, token);
}
return true;
}
/**
* function: send answer to the client
* sd: file descriptor
* message: formatting string in printf format
* ...: variable arguments for economics of formats
* return: true if not problem arise or else
* notes: the MSG_x have preformated for these use
**/
bool send_ans(int sd, char *message, ...){
char buffer[BUFSIZE];
va_list args;
va_start(args, message);
vsprintf(buffer, message, args);
va_end(args);
// send answer preformated and check errors
}
/**
* function: RETR operation
* sd: socket descriptor
* file_path: name of the RETR file
**/
void retr(int sd, char *file_path) {
FILE *file;
int bread;
long fsize;
char buffer[BUFSIZE];
// check if file exists if not inform error to client
// send a success message with the file length
// important delay for avoid problems with buffer size
sleep(1);
// send the file
// close the file
// send a completed transfer message
}
/**
* funcion: check valid credentials in ftpusers file
* user: login user name
* pass: user password
* return: true if found or false if not
**/
bool check_credentials(char *user, char *pass) {
FILE *file;
char *path = "./ftpusers", *line = NULL, credentials[100];
size_t line_size = 0;
bool found = false;
// make the credential string
sprintf(credentials, "%s:%s", user, pass);
// check if ftpusers file it's present
if ((file = fopen(path, "r"))==NULL) {
warn("Error opening %s", path);
return false;
}
// search for credential string
while (getline(&line, &line_size, file) != -1) {
strtok(line, "\n");
if (strcmp(line, credentials) == 0) {
found = true;
break;
}
}
// close file and release any pointers if necessary
fclose(file);
if (line) free(line);
// return search status
return found;
}
/**
* function: login process management
* sd: socket descriptor
* return: true if login is succesfully, false if not
**/
bool authenticate(int sd) {
char user[PARSIZE], pass[PARSIZE];
// wait to receive USER action
// ask for password
// wait to receive PASS action
// if credentials don't check denied login
// confirm login
}
/**
* function: execute all commands (RETR|QUIT)
* sd: socket descriptor
**/
void operate(int sd) {
char op[CMDSIZE], param[PARSIZE];
while (true) {
op[0] = param[0] = '\0';
// check for commands send by the client if not inform and exit
if (strcmp(op, "RETR") == 0) {
retr(sd, param);
} else if (strcmp(op, "QUIT") == 0) {
// send goodbye and close connection
break;
} else {
// invalid command
// furute use
}
}
}
/**
* Run with
* ./mysrv <SERVER_PORT>
**/
int main (int argc, char *argv[]) {
// arguments checking
if (argc < 2) {
errx(1, "Port expected as argument");
} else if (argc > 2) {
errx(1, "Too many arguments");
}
// reserve sockets and variables space
int master_sd, slave_sd;
struct sockaddr_in master_addr, slave_addr;
// create server socket and check errors
// bind master socket and check errors
// make it listen
// main loop
while (true) {
// accept connectiones sequentially and check errors
// send hello
// operate only if authenticate is true
}
// close server socket
return 0;
}