1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | #include <unistd.h> |
22 | #include <errno(*__errno_location ()).h> |
23 | #include <string.h> |
24 | #include <ctype.h> |
25 | #include <pwd.h> |
26 | #include <netdb.h> |
27 | #include <netinet/in.h> |
28 | |
29 | #include <ftpconn.h> |
30 | #include "priv.h" |
31 |
|
32 | static error_t |
33 | ftp_conn_login (struct ftp_conn *conn) |
34 | { |
35 | int reply; |
36 | error_t err = 0; |
37 | const struct ftp_conn_params *p = conn->params; |
38 | |
39 | err = ftp_conn_cmd (conn, "user", p->user ?: "anonymous", &reply, 0); |
| |
40 | |
41 | if (!err && reply == REPLY_NEED_ACCT332) |
| |
| 14 | | Assuming 'reply' is not equal to 332 | |
|
| |
42 | { |
43 | char *acct = p->acct; |
44 | if (!acct && conn->hooks && conn->hooks->get_login_param) |
45 | err = (* conn->hooks->get_login_param) (conn, |
46 | FTP_CONN_GET_LOGIN_PARAM_ACCT3, |
47 | &acct); |
48 | if (! err) |
49 | err = acct ? ftp_conn_cmd (conn, "acct", acct, &reply, 0) : EACCES((0x10 << 26) | ((13) & 0x3fff)); |
50 | if (acct && !p->acct) |
51 | free (acct); |
52 | } |
53 | |
54 | if (!err && reply == REPLY_NEED_PASS331) |
| 16 | | Assuming 'reply' is equal to 331 | |
|
| |
55 | { |
56 | char *pass = p->pass; |
57 | if (!pass && conn->hooks && conn->hooks->get_login_param) |
| 18 | | Assuming 'pass' is null | |
|
58 | err = (* conn->hooks->get_login_param) (conn, |
59 | FTP_CONN_GET_LOGIN_PARAM_PASS2, |
60 | &pass); |
61 | if (! err) |
| |
62 | { |
63 | if (pass) |
| |
64 | err = ftp_conn_cmd (conn, "pass", pass, &reply, 0); |
65 | else |
66 | { |
67 | pass = getenv ("USER"); |
68 | if (! pass) |
| 21 | | Assuming 'pass' is non-null | |
|
| |
69 | pass = getenv ("LOGNAME"); |
70 | if (! pass) |
| |
71 | { |
72 | struct passwd *pe = getpwuid (getuid ()); |
73 | pass = pe ? pe->pw_name : "?"; |
74 | } |
75 | |
76 | |
77 | pass = strdup (pass); |
| |
78 | if (pass) |
| 25 | | Assuming 'pass' is non-null | |
|
| |
79 | pass = realloc (pass, strlen (pass) + 1); |
| 27 | | Attempt to reallocate memory | |
|
80 | if (pass) |
| 28 | | Assuming 'pass' is null | |
|
| |
| |
81 | { |
82 | strcat (pass, "@"); |
83 | err = ftp_conn_cmd (conn, "pass", pass, &reply, 0); |
84 | } |
85 | else |
86 | err = ENOMEM((0x10 << 26) | ((12) & 0x3fff)); |
87 | } |
88 | } |
89 | if (pass && !p->pass) |
90 | free (pass); |
91 | } |
92 | |
93 | if (!err && reply != REPLY_LOGIN_OK230) |
| 31 | | Memory is never released; potential leak of memory pointed to by 'pass' |
|
94 | { |
95 | if (REPLY_IS_FAILURE (reply)((reply) >= 500 && (reply) < 600)) |
96 | err = EACCES((0x10 << 26) | ((13) & 0x3fff)); |
97 | else |
98 | err = unexpected_reply (conn, reply, 0, 0); |
99 | } |
100 | |
101 | return err; |
102 | } |
103 | |
104 | static error_t |
105 | ftp_conn_hello (struct ftp_conn *conn) |
106 | { |
107 | int reply; |
108 | error_t err; |
109 | |
110 | do |
111 | err = ftp_conn_get_reply (conn, &reply, 0); |
112 | while (!err && reply == REPLY_DELAY120); |
113 | |
114 | if (err) |
115 | return err; |
116 | |
117 | if (reply == REPLY_CLOSED421) |
118 | return ECONNREFUSED((0x10 << 26) | ((61) & 0x3fff)); |
119 | if (reply != REPLY_HELLO220) |
120 | return EGRATUITOUS((0x10 << 26) | ((105) & 0x3fff)); |
121 | |
122 | return 0; |
123 | } |
124 |
|
125 | |
126 | void |
127 | ftp_conn_set_syshooks (struct ftp_conn *conn, struct ftp_conn_syshooks *syshooks) |
128 | { |
129 | conn->syshooks = *syshooks; |
130 | } |
131 | |
132 | void |
133 | ftp_conn_choose_syshooks (struct ftp_conn *conn, const char *syst) |
134 | { |
135 | if (!syst || (strncasecmp (syst, "UNIX", 4) == 0 && !isalnum (syst[4])((*__ctype_b_loc ())[(int) ((syst[4]))] & (unsigned short int) _ISalnum))) |
136 | ftp_conn_set_syshooks (conn, &ftp_conn_unix_syshooks); |
137 | } |
138 | |
139 | |
140 | static error_t |
141 | ftp_conn_sysify (struct ftp_conn *conn) |
142 | { |
143 | int reply; |
144 | const char *txt; |
145 | error_t err = ftp_conn_cmd (conn, "syst", 0, &reply, &txt); |
146 | |
147 | if (! err) |
148 | { |
149 | if (reply == REPLY_SYSTYPE215 || |
150 | reply == REPLY_BAD_CMD500 || reply == REPLY_UNIMP_CMD502 || REPLY_NO_LOGIN530) |
151 | { |
152 | if (reply == REPLY_BAD_CMD500 || reply == REPLY_UNIMP_CMD502 |
153 | || reply == REPLY_NO_LOGIN530) |
154 | txt = 0; |
155 | if (conn->hooks && conn->hooks->choose_syshooks) |
156 | (*conn->hooks->choose_syshooks) (conn, txt); |
157 | else |
158 | ftp_conn_choose_syshooks (conn, txt); |
159 | conn->syshooks_valid = 1; |
160 | } |
161 | else |
162 | err = unexpected_reply (conn, reply, txt, 0); |
163 | } |
164 | |
165 | return err; |
166 | } |
167 |
|
168 | error_t |
169 | ftp_conn_open (struct ftp_conn *conn) |
170 | { |
171 | static int ftp_port = 0; |
172 | int csock; |
173 | error_t err; |
174 | struct sockaddr_in ftp_addr; |
175 | |
176 | if (conn->params->addr_type != AF_INET2) |
| |
177 | return EAFNOSUPPORT((0x10 << 26) | ((47) & 0x3fff)); |
178 | |
179 | if (! ftp_port) |
| |
180 | { |
181 | struct servent *se = getservbyname ("ftp", "tcp"); |
182 | if (! se) |
| 3 | | Assuming 'se' is non-null | |
|
| |
183 | return EGRATUITOUS((0x10 << 26) | ((105) & 0x3fff)); |
184 | ftp_port = se->s_port; |
185 | } |
186 | |
187 | if (conn->control >= 0) |
| |
188 | { |
189 | close (conn->control); |
190 | conn->control = -1; |
191 | } |
192 | memset (&conn->syshooks, 0, sizeof conn->syshooks); |
193 | |
194 | csock = socket (PF_INET2, SOCK_STREAMSOCK_STREAM, 0); |
195 | if (csock < 0) |
| 6 | | Assuming 'csock' is >= 0 | |
|
| |
196 | return errno(*__errno_location ()); |
197 | |
198 | ftp_addr.sin_len = sizeof ftp_addr; |
199 | ftp_addr.sin_family = conn->params->addr_type; |
200 | ftp_addr.sin_addr = *(struct in_addr *)conn->params->addr; |
201 | ftp_addr.sin_port = ftp_port; |
202 | |
203 | if (connect (csock, (struct sockaddr *)&ftp_addr, sizeof ftp_addr) < 0) |
| |
204 | { |
205 | err = errno(*__errno_location ()); |
206 | close (csock); |
207 | return err; |
208 | } |
209 | |
210 | conn->control = csock; |
211 | |
212 | err = ftp_conn_hello (conn); |
213 | |
214 | if (!err && conn->hooks && conn->hooks->opened) |
215 | (* conn->hooks->opened) (conn); |
216 | |
217 | if (! err) |
| |
218 | |
219 | ftp_conn_sysify (conn); |
220 | |
221 | if (! err) |
| |
222 | |
223 | err = ftp_conn_login (conn); |
| 11 | | Calling 'ftp_conn_login' | |
|
224 | |
225 | if (!err && !conn->syshooks_valid) |
226 | |
227 | err = ftp_conn_sysify (conn); |
228 | |
229 | if (!err && conn->type) |
230 | |
231 | { |
232 | int reply; |
233 | err = ftp_conn_cmd (conn, "type", conn->type, &reply, 0); |
234 | if (!err && reply != REPLY_OK200) |
235 | err = unexpected_reply (conn, reply, 0, 0); |
236 | } |
237 | |
238 | if (err) |
239 | ftp_conn_close (conn); |
240 | |
241 | return err; |
242 | } |
243 | |
244 | void |
245 | ftp_conn_close (struct ftp_conn *conn) |
246 | { |
247 | if (conn->control >= 0) |
248 | close (conn->control); |
249 | conn->control = -1; |
250 | if (conn->hooks && conn->hooks->closed) |
251 | (* conn->hooks->closed) (conn); |
252 | } |