00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "setup.h"
00035
00036 #ifndef CURL_DISABLE_FTP
00037 #ifdef HAVE_GSSAPI
00038
00039 #include <stdlib.h>
00040 #ifdef HAVE_NETDB_H
00041 #include <netdb.h>
00042 #endif
00043 #include <string.h>
00044 #include <gssapi/gssapi.h>
00045 #include <gssapi/gssapi_generic.h>
00046 #include <gssapi/gssapi_krb5.h>
00047
00048 #include "urldata.h"
00049 #include "base64.h"
00050 #include "ftp.h"
00051 #include "sendf.h"
00052 #include "krb4.h"
00053 #include "memory.h"
00054
00055
00056 #include "memdebug.h"
00057
00058 #define LOCAL_ADDR (&conn->local_addr)
00059 #define REMOTE_ADDR conn->ip_addr->ai_addr
00060
00061 static int
00062 krb5_check_prot(void *app_data, int level)
00063 {
00064 app_data = NULL;
00065 if(level == prot_confidential)
00066 return -1;
00067 return 0;
00068 }
00069
00070 static int
00071 krb5_decode(void *app_data, void *buf, int len, int level,
00072 struct connectdata *conn)
00073 {
00074 gss_ctx_id_t *context = app_data;
00075 OM_uint32 maj, min;
00076 gss_buffer_desc enc, dec;
00077
00078
00079 level = 0;
00080 conn = NULL;
00081
00082 enc.value = buf;
00083 enc.length = len;
00084 maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL);
00085 if(maj != GSS_S_COMPLETE) {
00086 if(len >= 4)
00087 strcpy(buf, "599 ");
00088 return -1;
00089 }
00090
00091 memcpy(buf, dec.value, dec.length);
00092 len = dec.length;
00093 gss_release_buffer(&min, &dec);
00094
00095 return len;
00096 }
00097
00098 static int
00099 krb5_overhead(void *app_data, int level, int len)
00100 {
00101
00102 app_data = NULL;
00103 level = 0;
00104 len = 0;
00105 return 0;
00106 }
00107
00108 static int
00109 krb5_encode(void *app_data, void *from, int length, int level, void **to,
00110 struct connectdata *conn)
00111 {
00112 gss_ctx_id_t *context = app_data;
00113 gss_buffer_desc dec, enc;
00114 OM_uint32 maj, min;
00115 int state;
00116 int len;
00117
00118
00119 conn = NULL;
00120
00121 dec.value = from;
00122 dec.length = length;
00123 maj = gss_seal(&min, *context,
00124 level == prot_private,
00125 GSS_C_QOP_DEFAULT,
00126 &dec, &state, &enc);
00127
00128 if(maj != GSS_S_COMPLETE)
00129 return -1;
00130
00131
00132 *to = malloc(enc.length);
00133 if(!*to)
00134 return -1;
00135 memcpy(*to, enc.value, enc.length);
00136 len = enc.length;
00137 gss_release_buffer(&min, &enc);
00138 return len;
00139 }
00140
00141 static int
00142 krb5_auth(void *app_data, struct connectdata *conn)
00143 {
00144 int ret;
00145 char *p;
00146 const char *host = conn->dns_entry->addr->ai_canonname;
00147 ssize_t nread;
00148 unsigned int l = sizeof(conn->local_addr);
00149 struct SessionHandle *data = conn->data;
00150 CURLcode result;
00151 const char *service = "ftp", *srv_host = "host";
00152 gss_buffer_desc gssbuf, _gssresp, *gssresp;
00153 OM_uint32 maj, min;
00154 gss_name_t gssname;
00155 gss_ctx_id_t *context = app_data;
00156 struct gss_channel_bindings_struct chan;
00157
00158 if(getsockname(conn->sock[FIRSTSOCKET],
00159 (struct sockaddr *)LOCAL_ADDR, &l) < 0)
00160 perror("getsockname()");
00161
00162 chan.initiator_addrtype = GSS_C_AF_INET;
00163 chan.initiator_address.length = l - 4;
00164 chan.initiator_address.value = &((struct sockaddr_in *)LOCAL_ADDR)->sin_addr.s_addr;
00165 chan.acceptor_addrtype = GSS_C_AF_INET;
00166 chan.acceptor_address.length = l - 4;
00167 chan.acceptor_address.value = &((struct sockaddr_in *)REMOTE_ADDR)->sin_addr.s_addr;
00168 chan.application_data.length = 0;
00169 chan.application_data.value = NULL;
00170
00171
00172 while(1) {
00173
00174 if(service == srv_host) {
00175 result = Curl_ftpsendf(conn, "AUTH GSSAPI");
00176
00177 if(result)
00178 return -2;
00179 if(Curl_GetFTPResponse(&nread, conn, NULL))
00180 return -1;
00181
00182 if(data->state.buffer[0] != '3')
00183 return -1;
00184 }
00185
00186 gssbuf.value = data->state.buffer;
00187 gssbuf.length = snprintf(gssbuf.value, BUFSIZE, "%s@%s", service, host);
00188 maj = gss_import_name(&min, &gssbuf, gss_nt_service_name, &gssname);
00189 if(maj != GSS_S_COMPLETE) {
00190 gss_release_name(&min, &gssname);
00191 if(service == srv_host) {
00192 Curl_failf(data, "Error importing service name %s", gssbuf.value);
00193 return AUTH_ERROR;
00194 }
00195 service = srv_host;
00196 continue;
00197 }
00198 {
00199 gss_OID t;
00200 gss_display_name(&min, gssname, &gssbuf, &t);
00201 Curl_infof(data, "Trying against %s\n", gssbuf.value);
00202 gss_release_buffer(&min, &gssbuf);
00203 }
00204 gssresp = GSS_C_NO_BUFFER;
00205 *context = GSS_C_NO_CONTEXT;
00206
00207 do {
00208 ret = AUTH_OK;
00209 maj = gss_init_sec_context(&min,
00210 GSS_C_NO_CREDENTIAL,
00211 context,
00212 gssname,
00213 GSS_C_NO_OID,
00214 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
00215 0,
00216 &chan,
00217 gssresp,
00218 NULL,
00219 &gssbuf,
00220 NULL,
00221 NULL);
00222
00223 if(gssresp) {
00224 free(_gssresp.value);
00225 gssresp = NULL;
00226 }
00227
00228 if(maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
00229 Curl_infof(data, "Error creating security context");
00230 ret = AUTH_ERROR;
00231 break;
00232 }
00233
00234 if(gssbuf.length != 0) {
00235 if(Curl_base64_encode(data, (char *)gssbuf.value, gssbuf.length, &p) < 1) {
00236 Curl_infof(data, "Out of memory base64-encoding");
00237 ret = AUTH_CONTINUE;
00238 break;
00239 }
00240
00241 result = Curl_ftpsendf(conn, "ADAT %s", p);
00242
00243 free(p);
00244
00245 if(result) {
00246 ret = -2;
00247 break;
00248 }
00249
00250 if(Curl_GetFTPResponse(&nread, conn, NULL)) {
00251 ret = -1;
00252 break;
00253 }
00254
00255 if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3'){
00256 Curl_infof(data, "Server didn't accept auth data\n");
00257 ret = AUTH_ERROR;
00258 break;
00259 }
00260
00261 p = data->state.buffer + 4;
00262 p = strstr(p, "ADAT=");
00263 if(p) {
00264 _gssresp.length = Curl_base64_decode(p + 5, (unsigned char **)&_gssresp.value);
00265 if(_gssresp.length < 1) {
00266 Curl_failf(data, "Out of memory base64-encoding");
00267 ret = AUTH_CONTINUE;
00268 break;
00269 }
00270 }
00271
00272 gssresp = &_gssresp;
00273 }
00274 } while(maj == GSS_S_CONTINUE_NEEDED);
00275
00276 gss_release_name(&min, &gssname);
00277
00278 if(gssresp)
00279 free(_gssresp.value);
00280
00281 if(ret == AUTH_OK || service == srv_host)
00282 return ret;
00283
00284 service = srv_host;
00285 }
00286 }
00287
00288 struct Curl_sec_client_mech Curl_krb5_client_mech = {
00289 "GSSAPI",
00290 sizeof(gss_ctx_id_t),
00291 NULL,
00292 krb5_auth,
00293 NULL,
00294 krb5_check_prot,
00295 krb5_overhead,
00296 krb5_encode,
00297 krb5_decode
00298 };
00299
00300 #endif
00301 #endif