| 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 | bzero (&conn->syshooks, 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 | } |