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