1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1985, 1989 Regents of the University of California. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include "ftp_var.h" 40 #include <sys/types.h> 41 #include <gssapi/gssapi.h> 42 #include <gssapi/gssapi_ext.h> 43 44 int auth_type; /* Authentication succeeded? If so, what type? */ 45 46 char *radix_error(int); 47 static void get_inet_addr_info(struct sockaddr_in6 *, gss_buffer_t); 48 49 static char *radixN = 50 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 51 static char radix_pad = '='; 52 53 /* 54 * authenticate the user, if auth_type is AUTHTYPE_NONE 55 * 56 * Returns: 0 if there is no auth type 57 * 1 if success 58 * 2 if failure 59 */ 60 61 gss_OID mechoid; 62 gss_ctx_id_t gcontext; /* global gss security context */ 63 static const char *gss_trials[] = { "ftp", "host" }; 64 /* the number of elements in gss_trials array */ 65 static const int n_gss_trials = sizeof (gss_trials)/sizeof (char *); 66 char *reply_parse; 67 68 int 69 do_auth(void) 70 { 71 int oldverbose = verbose; 72 uchar_t *out_buf = NULL; 73 size_t outlen; 74 int i; 75 76 if (auth_type != AUTHTYPE_NONE) 77 return (1); /* auth already succeeded */ 78 79 /* Other auth types go here ... */ 80 81 if (command("AUTH %s", "GSSAPI") == CONTINUE) { 82 OM_uint32 maj_stat, min_stat; 83 gss_name_t target_name; 84 gss_buffer_desc send_tok, recv_tok, *token_ptr; 85 gss_buffer_desc temp_buf; 86 char stbuf[FTPBUFSIZ]; 87 int comcode, trial; 88 int req_flags; 89 struct gss_channel_bindings_struct chan; 90 91 get_inet_addr_info(&myctladdr, &temp_buf); 92 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */ 93 chan.initiator_address.length = temp_buf.length; 94 chan.initiator_address.value = malloc(temp_buf.length); 95 memcpy(chan.initiator_address.value, temp_buf.value, 96 temp_buf.length); 97 98 get_inet_addr_info(&remctladdr, &temp_buf); 99 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */ 100 chan.acceptor_address.length = temp_buf.length; 101 chan.acceptor_address.value = malloc(temp_buf.length); 102 memcpy(chan.acceptor_address.value, temp_buf.value, 103 temp_buf.length); 104 105 chan.application_data.length = 0; 106 chan.application_data.value = 0; 107 108 if (verbose) 109 (void) printf("GSSAPI accepted as authentication type\n"); 110 111 /* set the forward flag */ 112 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; 113 114 if (fflag) 115 req_flags |= GSS_C_DELEG_FLAG; 116 117 /* blob from gss-client */ 118 for (trial = 0; trial < n_gss_trials; trial++) { 119 /* ftp@hostname first, then host@hostname */ 120 /* the V5 GSSAPI binding canonicalizes this for us... */ 121 (void) snprintf(stbuf, FTPBUFSIZ, "%s@%s", 122 gss_trials[trial], hostname); 123 if (debug) 124 (void) fprintf(stderr, 125 "Trying to authenticate to <%s>\n", stbuf); 126 127 send_tok.value = stbuf; 128 send_tok.length = strlen(stbuf) + 1; 129 maj_stat = gss_import_name(&min_stat, &send_tok, 130 GSS_C_NT_HOSTBASED_SERVICE, &target_name); 131 132 if (maj_stat != GSS_S_COMPLETE) { 133 user_gss_error(maj_stat, min_stat, "parsing name"); 134 (void) fprintf(stderr, "name parsed <%s>\n", stbuf); 135 continue; 136 } 137 138 token_ptr = GSS_C_NO_BUFFER; 139 gcontext = GSS_C_NO_CONTEXT; /* structure copy */ 140 141 do { 142 if (debug) 143 (void) fprintf(stderr, 144 "calling gss_init_sec_context\n"); 145 146 if (mechstr && !mechoid && 147 __gss_mech_to_oid(mechstr, (gss_OID*)&mechoid) != 148 GSS_S_COMPLETE) 149 (void) printf("do_auth: %s: not a valid " 150 "security mechanism\n", mechstr); 151 152 if (!mechoid) 153 mechoid = GSS_C_NULL_OID; 154 155 maj_stat = gss_init_sec_context(&min_stat, 156 GSS_C_NO_CREDENTIAL, 157 &gcontext, 158 target_name, 159 mechoid, 160 req_flags, 161 0, 162 &chan, /* channel bindings */ 163 token_ptr, 164 NULL, /* ignore mech type */ 165 &send_tok, 166 NULL, /* ignore ret_flags */ 167 NULL); /* ignore time_rec */ 168 169 if (maj_stat != GSS_S_COMPLETE && 170 maj_stat != GSS_S_CONTINUE_NEEDED) { 171 172 /* return an error if this is NOT the ftp ticket */ 173 if (strcmp(gss_trials[trial], "ftp")) 174 user_gss_error(maj_stat, min_stat, 175 "initializing context"); 176 177 (void) gss_release_name(&min_stat, &target_name); 178 /* could just be that we missed on the service name */ 179 goto outer_loop; 180 181 } 182 183 if (send_tok.length != 0) { 184 int len = send_tok.length; 185 reply_parse = "ADAT="; /* for command() later */ 186 oldverbose = verbose; 187 verbose = (trial == n_gss_trials-1)?0:-1; 188 189 outlen = ENCODELEN(send_tok.length); 190 out_buf = (uchar_t *)malloc(outlen); 191 if (out_buf == NULL) { 192 (void) fprintf(stderr, "memory error allocating " 193 "auth buffer\n"); 194 maj_stat = GSS_S_FAILURE; 195 goto outer_loop; 196 } 197 auth_error = radix_encode(send_tok.value, out_buf, 198 outlen, &len, 0); 199 200 if (auth_error) { 201 (void) fprintf(stderr, "Base 64 encoding failed: %s\n", 202 radix_error(auth_error)); 203 } else if ((comcode = command("ADAT %s", out_buf)) 204 != COMPLETE /* && comcode != 3 (335)*/) { 205 206 if (trial == n_gss_trials-1) { 207 (void) fprintf(stderr, "GSSAPI ADAT failed (%d)\n", 208 comcode); 209 210 /* force out of loop */ 211 maj_stat = GSS_S_FAILURE; 212 } 213 214 /* 215 * backoff to the v1 gssapi is still possible. 216 * Send a new AUTH command. If that fails, 217 * terminate the loop 218 */ 219 if (command("AUTH %s", "GSSAPI") != CONTINUE) { 220 (void) fprintf(stderr, 221 "GSSAPI ADAT failed, AUTH restart failed\n"); 222 /* force out of loop */ 223 maj_stat = GSS_S_FAILURE; 224 } 225 226 goto outer_loop; 227 } else if (!reply_parse) { 228 (void) fprintf(stderr, 229 "No authentication data received from server\n"); 230 if (maj_stat == GSS_S_COMPLETE) { 231 (void) fprintf(stderr, 232 "...but no more was needed\n"); 233 goto gss_complete_loop; 234 } else { 235 user_gss_error(maj_stat, min_stat, "no reply."); 236 goto gss_complete_loop; 237 } 238 } else if (auth_error = radix_encode((uchar_t *) 239 reply_parse, out_buf, outlen, &i, 1)) { 240 (void) fprintf(stderr, 241 "Base 64 decoding failed: %s\n", 242 radix_error(auth_error)); 243 } else { 244 /* everything worked */ 245 token_ptr = &recv_tok; 246 recv_tok.value = out_buf; 247 recv_tok.length = i; 248 continue; 249 } /* end if (auth_error) */ 250 251 /* get out of loop clean */ 252 gss_complete_loop: 253 trial = n_gss_trials-1; 254 gss_release_buffer(&min_stat, &send_tok); 255 gss_release_name(&min_stat, &target_name); 256 goto outer_loop; 257 } /* end if (send_tok.length != 0) */ 258 259 } while (maj_stat == GSS_S_CONTINUE_NEEDED); 260 261 outer_loop: 262 if (maj_stat == GSS_S_COMPLETE) 263 break; 264 265 } /* end for loop */ 266 267 verbose = oldverbose; 268 if (out_buf != NULL) 269 free(out_buf); 270 271 if (maj_stat == GSS_S_COMPLETE) { 272 (void) printf("GSSAPI authentication succeeded\n"); 273 reply_parse = NULL; 274 auth_type = AUTHTYPE_GSSAPI; 275 return (1); 276 } else { 277 (void) fprintf(stderr, "GSSAPI authentication failed\n"); 278 reply_parse = NULL; 279 } 280 } /* end if (command...) */ 281 282 /* Other auth types go here ... */ 283 284 return (0); 285 } 286 287 /* 288 * Get the information for the channel structure. 289 */ 290 void 291 get_inet_addr_info(struct sockaddr_in6 *in_ipaddr, gss_buffer_t in_buffer) 292 { 293 size_t length; 294 char *value; 295 296 if (in_ipaddr == NULL) { 297 in_buffer->length = 0; 298 in_buffer->value = NULL; 299 return; 300 } 301 302 /* get the initiator address.value and address.length */ 303 304 if (in_ipaddr->sin6_family == AF_INET6) { 305 struct in_addr in_ipv4addr; 306 struct sockaddr_in6 *sin6 = 307 (struct sockaddr_in6 *)in_ipaddr; 308 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 309 IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, 310 &in_ipv4addr); 311 in_buffer->length = length = sizeof (struct in_addr); 312 in_buffer->value = value = malloc(length); 313 memcpy(value, &in_ipv4addr, length); 314 } else { 315 in_buffer->length = length = sizeof (struct in6_addr); 316 in_buffer->value = value = malloc(length); 317 memcpy(value, &(sin6->sin6_addr.s6_addr), 318 length); 319 } 320 } else { 321 in_buffer->length = length = sizeof (struct in_addr); 322 in_buffer->value = value = malloc(in_buffer->length); 323 memcpy(value, 324 &((struct sockaddr_in *)(in_ipaddr))->sin_addr, 325 length); 326 } 327 } 328 329 int 330 radix_encode(uchar_t *inbuf, uchar_t *outbuf, size_t buflen, 331 int *outlen, int decode) 332 { 333 int i, j, D; 334 char *p; 335 uchar_t c; 336 337 if (decode) { 338 for (i = j = 0; 339 inbuf[i] && inbuf[i] != radix_pad && (j < buflen); 340 i++) { 341 if ((p = strchr(radixN, inbuf[i])) == NULL) 342 return (1); 343 D = p - radixN; 344 switch (i&3) { 345 case 0: 346 outbuf[j] = D<<2; 347 break; 348 case 1: 349 outbuf[j++] |= D>>4; 350 outbuf[j] = (D&15)<<4; 351 break; 352 case 2: 353 outbuf[j++] |= D>>2; 354 outbuf[j] = (D&3)<<6; 355 break; 356 case 3: 357 outbuf[j++] |= D; 358 } 359 } 360 if (j == buflen && (inbuf[i] && inbuf[i] != radix_pad)) { 361 return (4); 362 } 363 switch (i&3) { 364 case 1: return (3); 365 case 2: if (D&15) 366 return (3); 367 if (strcmp((char *)&inbuf[i], "==")) 368 return (2); 369 break; 370 case 3: if (D&3) 371 return (3); 372 if (strcmp((char *)&inbuf[i], "=")) 373 return (2); 374 } 375 *outlen = j; 376 } else { 377 for (i = j = 0; i < *outlen && j < buflen; i++) 378 switch (i%3) { 379 case 0: 380 outbuf[j++] = radixN[inbuf[i]>>2]; 381 c = (inbuf[i]&3)<<4; 382 break; 383 case 1: 384 outbuf[j++] = radixN[c|inbuf[i]>>4]; 385 c = (inbuf[i]&15)<<2; 386 break; 387 case 2: 388 outbuf[j++] = radixN[c|inbuf[i]>>6]; 389 outbuf[j++] = radixN[inbuf[i]&63]; 390 c = 0; 391 } 392 if (j == buflen && i < *outlen) { 393 return (4); 394 } 395 if (i%3) 396 outbuf[j++] = radixN[c]; 397 switch (i%3) { 398 case 1: 399 outbuf[j++] = radix_pad; 400 /* FALLTHROUGH */ 401 case 2: 402 outbuf[j++] = radix_pad; 403 break; 404 } 405 outbuf[*outlen = j] = '\0'; 406 } 407 return (0); 408 } 409 410 char * 411 radix_error(int e) 412 { 413 switch (e) { 414 case 0: return ("Success"); 415 case 1: return ("Bad character in encoding"); 416 case 2: return ("Encoding not properly padded"); 417 case 3: return ("Decoded # of bits not a multiple of 8"); 418 case 4: return ("Buffer size error"); 419 default: return ("Unknown error"); 420 } 421 } 422