1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 6*0Sstevel@tonic-gate 7*0Sstevel@tonic-gate /* Generic SASL plugin utility functions 8*0Sstevel@tonic-gate * Rob Siemborski 9*0Sstevel@tonic-gate * $Id: plugin_common.c,v 1.13 2003/02/13 19:56:05 rjs3 Exp $ 10*0Sstevel@tonic-gate */ 11*0Sstevel@tonic-gate /* 12*0Sstevel@tonic-gate * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 15*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 16*0Sstevel@tonic-gate * are met: 17*0Sstevel@tonic-gate * 18*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 19*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 20*0Sstevel@tonic-gate * 21*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 22*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in 23*0Sstevel@tonic-gate * the documentation and/or other materials provided with the 24*0Sstevel@tonic-gate * distribution. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * 3. The name "Carnegie Mellon University" must not be used to 27*0Sstevel@tonic-gate * endorse or promote products derived from this software without 28*0Sstevel@tonic-gate * prior written permission. For permission or any other legal 29*0Sstevel@tonic-gate * details, please contact 30*0Sstevel@tonic-gate * Office of Technology Transfer 31*0Sstevel@tonic-gate * Carnegie Mellon University 32*0Sstevel@tonic-gate * 5000 Forbes Avenue 33*0Sstevel@tonic-gate * Pittsburgh, PA 15213-3890 34*0Sstevel@tonic-gate * (412) 268-4387, fax: (412) 268-7395 35*0Sstevel@tonic-gate * tech-transfer@andrew.cmu.edu 36*0Sstevel@tonic-gate * 37*0Sstevel@tonic-gate * 4. Redistributions of any form whatsoever must retain the following 38*0Sstevel@tonic-gate * acknowledgment: 39*0Sstevel@tonic-gate * "This product includes software developed by Computing Services 40*0Sstevel@tonic-gate * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 41*0Sstevel@tonic-gate * 42*0Sstevel@tonic-gate * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 43*0Sstevel@tonic-gate * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 44*0Sstevel@tonic-gate * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 45*0Sstevel@tonic-gate * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 46*0Sstevel@tonic-gate * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 47*0Sstevel@tonic-gate * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 48*0Sstevel@tonic-gate * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 49*0Sstevel@tonic-gate */ 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #include <config.h> 52*0Sstevel@tonic-gate #ifndef macintosh 53*0Sstevel@tonic-gate #ifdef WIN32 54*0Sstevel@tonic-gate # include <winsock.h> 55*0Sstevel@tonic-gate #else 56*0Sstevel@tonic-gate # include <sys/socket.h> 57*0Sstevel@tonic-gate # include <netinet/in.h> 58*0Sstevel@tonic-gate # include <arpa/inet.h> 59*0Sstevel@tonic-gate # include <netdb.h> 60*0Sstevel@tonic-gate #endif /* WIN32 */ 61*0Sstevel@tonic-gate #endif /* macintosh */ 62*0Sstevel@tonic-gate #ifdef HAVE_UNISTD_H 63*0Sstevel@tonic-gate #include <unistd.h> 64*0Sstevel@tonic-gate #endif 65*0Sstevel@tonic-gate #include <fcntl.h> 66*0Sstevel@tonic-gate #include <sasl.h> 67*0Sstevel@tonic-gate #include <saslutil.h> 68*0Sstevel@tonic-gate #include <saslplug.h> 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate #include <errno.h> 71*0Sstevel@tonic-gate #include <ctype.h> 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate #ifdef HAVE_INTTYPES_H 74*0Sstevel@tonic-gate #include <inttypes.h> 75*0Sstevel@tonic-gate #endif 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate #include "plugin_common.h" 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate /* translate IPv4 mapped IPv6 address to IPv4 address */ 80*0Sstevel@tonic-gate static void sockaddr_unmapped( 81*0Sstevel@tonic-gate #ifdef IN6_IS_ADDR_V4MAPPED 82*0Sstevel@tonic-gate struct sockaddr *sa, socklen_t *len 83*0Sstevel@tonic-gate #else 84*0Sstevel@tonic-gate struct sockaddr *sa __attribute__((unused)), 85*0Sstevel@tonic-gate socklen_t *len __attribute__((unused)) 86*0Sstevel@tonic-gate #endif 87*0Sstevel@tonic-gate ) 88*0Sstevel@tonic-gate { 89*0Sstevel@tonic-gate #ifdef IN6_IS_ADDR_V4MAPPED 90*0Sstevel@tonic-gate struct sockaddr_in6 *sin6; 91*0Sstevel@tonic-gate struct sockaddr_in *sin4; 92*0Sstevel@tonic-gate uint32_t addr; 93*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 94*0Sstevel@tonic-gate in_port_t port; 95*0Sstevel@tonic-gate #else 96*0Sstevel@tonic-gate int port; 97*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate if (sa->sa_family != AF_INET6) 100*0Sstevel@tonic-gate return; 101*0Sstevel@tonic-gate /* LINTED pointer alignment */ 102*0Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)sa; 103*0Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED((&sin6->sin6_addr))) 104*0Sstevel@tonic-gate return; 105*0Sstevel@tonic-gate /* LINTED pointer alignment */ 106*0Sstevel@tonic-gate sin4 = (struct sockaddr_in *)sa; 107*0Sstevel@tonic-gate /* LINTED pointer alignment */ 108*0Sstevel@tonic-gate addr = *(uint32_t *)&sin6->sin6_addr.s6_addr[12]; 109*0Sstevel@tonic-gate port = sin6->sin6_port; 110*0Sstevel@tonic-gate memset(sin4, 0, sizeof(struct sockaddr_in)); 111*0Sstevel@tonic-gate sin4->sin_addr.s_addr = addr; 112*0Sstevel@tonic-gate sin4->sin_port = port; 113*0Sstevel@tonic-gate sin4->sin_family = AF_INET; 114*0Sstevel@tonic-gate #ifdef HAVE_SOCKADDR_SA_LEN 115*0Sstevel@tonic-gate sin4->sin_len = sizeof(struct sockaddr_in); 116*0Sstevel@tonic-gate #endif 117*0Sstevel@tonic-gate *len = sizeof(struct sockaddr_in); 118*0Sstevel@tonic-gate #else 119*0Sstevel@tonic-gate return; 120*0Sstevel@tonic-gate #endif 121*0Sstevel@tonic-gate } 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate int _plug_ipfromstring(const sasl_utils_t *utils, const char *addr, 124*0Sstevel@tonic-gate struct sockaddr *out, socklen_t outlen) 125*0Sstevel@tonic-gate { 126*0Sstevel@tonic-gate int i, j; 127*0Sstevel@tonic-gate socklen_t len; 128*0Sstevel@tonic-gate #ifdef WINNT /* _SUN_SDK_ */ 129*0Sstevel@tonic-gate struct sockaddr_in ss; 130*0Sstevel@tonic-gate #else 131*0Sstevel@tonic-gate struct sockaddr_storage ss; 132*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 133*0Sstevel@tonic-gate struct addrinfo hints, *ai = NULL; 134*0Sstevel@tonic-gate char hbuf[NI_MAXHOST]; 135*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 136*0Sstevel@tonic-gate const char *start, *end, *p; 137*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate if(!utils || !addr || !out) { 140*0Sstevel@tonic-gate if(utils) PARAMERROR( utils ); 141*0Sstevel@tonic-gate return SASL_BADPARAM; 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 145*0Sstevel@tonic-gate end = strchr(addr, ']'); 146*0Sstevel@tonic-gate if (end != NULL) { 147*0Sstevel@tonic-gate /* This an rfc 2732 ipv6 address */ 148*0Sstevel@tonic-gate start = strchr(addr, '['); 149*0Sstevel@tonic-gate if (start >= end || start == NULL) { 150*0Sstevel@tonic-gate if(utils) PARAMERROR( utils ); 151*0Sstevel@tonic-gate return SASL_BADPARAM; 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate for (i = 0, p = start + 1; p < end; p++) { 154*0Sstevel@tonic-gate hbuf[i++] = *p; 155*0Sstevel@tonic-gate if (i >= NI_MAXHOST) 156*0Sstevel@tonic-gate break; 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate p = strchr(end, ':'); 159*0Sstevel@tonic-gate if (p == NULL) 160*0Sstevel@tonic-gate p = end + 1; 161*0Sstevel@tonic-gate else 162*0Sstevel@tonic-gate p = p + 1; 163*0Sstevel@tonic-gate } else { 164*0Sstevel@tonic-gate for (i = 0; addr[i] != '\0' && addr[i] != ';'; ) { 165*0Sstevel@tonic-gate hbuf[i] = addr[i]; 166*0Sstevel@tonic-gate if (++i >= NI_MAXHOST) 167*0Sstevel@tonic-gate break; 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate if (addr[i] == ';') 170*0Sstevel@tonic-gate p = &addr[i+1]; 171*0Sstevel@tonic-gate else 172*0Sstevel@tonic-gate p = &addr[i]; 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate if (i >= NI_MAXHOST) { 175*0Sstevel@tonic-gate if(utils) PARAMERROR( utils ); 176*0Sstevel@tonic-gate return SASL_BADPARAM; 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate hbuf[i] = '\0'; 179*0Sstevel@tonic-gate for (j = 0; p[j] != '\0'; j++) 180*0Sstevel@tonic-gate if (!isdigit((int)(p[j]))) { 181*0Sstevel@tonic-gate PARAMERROR( utils ); 182*0Sstevel@tonic-gate return SASL_BADPARAM; 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate #else 185*0Sstevel@tonic-gate /* Parse the address */ 186*0Sstevel@tonic-gate for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) { 187*0Sstevel@tonic-gate if (i >= NI_MAXHOST) { 188*0Sstevel@tonic-gate if(utils) PARAMERROR( utils ); 189*0Sstevel@tonic-gate return SASL_BADPARAM; 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate hbuf[i] = addr[i]; 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate hbuf[i] = '\0'; 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate if (addr[i] == ';') 196*0Sstevel@tonic-gate i++; 197*0Sstevel@tonic-gate /* XXX/FIXME: Do we need this check? */ 198*0Sstevel@tonic-gate for (j = i; addr[j] != '\0'; j++) 199*0Sstevel@tonic-gate if (!isdigit((int)(addr[j]))) { 200*0Sstevel@tonic-gate PARAMERROR( utils ); 201*0Sstevel@tonic-gate return SASL_BADPARAM; 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate memset(&hints, 0, sizeof(hints)); 206*0Sstevel@tonic-gate hints.ai_family = PF_UNSPEC; 207*0Sstevel@tonic-gate hints.ai_socktype = SOCK_STREAM; 208*0Sstevel@tonic-gate hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 211*0Sstevel@tonic-gate if (getaddrinfo(hbuf, p, &hints, &ai) != 0) { 212*0Sstevel@tonic-gate #else 213*0Sstevel@tonic-gate if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0) { 214*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 215*0Sstevel@tonic-gate PARAMERROR( utils ); 216*0Sstevel@tonic-gate return SASL_BADPARAM; 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate len = ai->ai_addrlen; 220*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 221*0Sstevel@tonic-gate if (len > sizeof(ss)) 222*0Sstevel@tonic-gate return (SASL_BUFOVER); 223*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 224*0Sstevel@tonic-gate memcpy(&ss, ai->ai_addr, len); 225*0Sstevel@tonic-gate freeaddrinfo(ai); 226*0Sstevel@tonic-gate sockaddr_unmapped((struct sockaddr *)&ss, &len); 227*0Sstevel@tonic-gate if (outlen < len) { 228*0Sstevel@tonic-gate PARAMERROR( utils ); 229*0Sstevel@tonic-gate return SASL_BUFOVER; 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate memcpy(out, &ss, len); 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate return SASL_OK; 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate int _plug_iovec_to_buf(const sasl_utils_t *utils, const struct iovec *vec, 238*0Sstevel@tonic-gate unsigned numiov, buffer_info_t **output) 239*0Sstevel@tonic-gate { 240*0Sstevel@tonic-gate unsigned i; 241*0Sstevel@tonic-gate int ret; 242*0Sstevel@tonic-gate buffer_info_t *out; 243*0Sstevel@tonic-gate char *pos; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate if(!utils || !vec || !output) { 246*0Sstevel@tonic-gate if(utils) PARAMERROR( utils ); 247*0Sstevel@tonic-gate return SASL_BADPARAM; 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if(!(*output)) { 251*0Sstevel@tonic-gate *output = utils->malloc(sizeof(buffer_info_t)); 252*0Sstevel@tonic-gate if(!*output) { 253*0Sstevel@tonic-gate MEMERROR(utils); 254*0Sstevel@tonic-gate return SASL_NOMEM; 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate memset(*output,0,sizeof(buffer_info_t)); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate out = *output; 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate out->curlen = 0; 262*0Sstevel@tonic-gate for(i=0; i<numiov; i++) 263*0Sstevel@tonic-gate out->curlen += vec[i].iov_len; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate ret = _plug_buf_alloc(utils, &out->data, &out->reallen, out->curlen); 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate if(ret != SASL_OK) { 268*0Sstevel@tonic-gate MEMERROR(utils); 269*0Sstevel@tonic-gate return SASL_NOMEM; 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate memset(out->data, 0, out->reallen); 273*0Sstevel@tonic-gate pos = out->data; 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate for(i=0; i<numiov; i++) { 276*0Sstevel@tonic-gate memcpy(pos, vec[i].iov_base, vec[i].iov_len); 277*0Sstevel@tonic-gate pos += vec[i].iov_len; 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate return SASL_OK; 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate /* Basically a conditional call to realloc(), if we need more */ 284*0Sstevel@tonic-gate int _plug_buf_alloc(const sasl_utils_t *utils, char **rwbuf, 285*0Sstevel@tonic-gate unsigned *curlen, unsigned newlen) 286*0Sstevel@tonic-gate { 287*0Sstevel@tonic-gate if(!utils || !rwbuf || !curlen) { 288*0Sstevel@tonic-gate PARAMERROR(utils); 289*0Sstevel@tonic-gate return SASL_BADPARAM; 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate if(!(*rwbuf)) { 293*0Sstevel@tonic-gate *rwbuf = utils->malloc(newlen); 294*0Sstevel@tonic-gate if (*rwbuf == NULL) { 295*0Sstevel@tonic-gate *curlen = 0; 296*0Sstevel@tonic-gate MEMERROR(utils); 297*0Sstevel@tonic-gate return SASL_NOMEM; 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate *curlen = newlen; 300*0Sstevel@tonic-gate } else if(*rwbuf && *curlen < newlen) { 301*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 302*0Sstevel@tonic-gate unsigned needed = 2*(*curlen); 303*0Sstevel@tonic-gate #else 304*0Sstevel@tonic-gate size_t needed = 2*(*curlen); 305*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate while(needed < newlen) 308*0Sstevel@tonic-gate needed *= 2; 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate *rwbuf = utils->realloc(*rwbuf, needed); 311*0Sstevel@tonic-gate if (*rwbuf == NULL) { 312*0Sstevel@tonic-gate *curlen = 0; 313*0Sstevel@tonic-gate MEMERROR(utils); 314*0Sstevel@tonic-gate return SASL_NOMEM; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate *curlen = needed; 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate return SASL_OK; 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate /* copy a string */ 323*0Sstevel@tonic-gate int _plug_strdup(const sasl_utils_t * utils, const char *in, 324*0Sstevel@tonic-gate char **out, int *outlen) 325*0Sstevel@tonic-gate { 326*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 327*0Sstevel@tonic-gate int len; 328*0Sstevel@tonic-gate #else 329*0Sstevel@tonic-gate size_t len = strlen(in); 330*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate if(!utils || !in || !out) { 333*0Sstevel@tonic-gate if(utils) PARAMERROR(utils); 334*0Sstevel@tonic-gate return SASL_BADPARAM; 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 338*0Sstevel@tonic-gate len = strlen(in); 339*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 340*0Sstevel@tonic-gate *out = utils->malloc(len + 1); 341*0Sstevel@tonic-gate if (!*out) { 342*0Sstevel@tonic-gate MEMERROR(utils); 343*0Sstevel@tonic-gate return SASL_NOMEM; 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate strcpy((char *) *out, in); 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate if (outlen) 349*0Sstevel@tonic-gate *outlen = len; 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate return SASL_OK; 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate void _plug_free_string(const sasl_utils_t *utils, char **str) 355*0Sstevel@tonic-gate { 356*0Sstevel@tonic-gate size_t len; 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate if (!utils || !str || !(*str)) return; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate len = strlen(*str); 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate utils->erasebuffer(*str, len); 363*0Sstevel@tonic-gate utils->free(*str); 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate *str=NULL; 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate void _plug_free_secret(const sasl_utils_t *utils, sasl_secret_t **secret) 369*0Sstevel@tonic-gate { 370*0Sstevel@tonic-gate if(!utils || !secret || !(*secret)) return; 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 373*0Sstevel@tonic-gate utils->erasebuffer((char *)(*secret)->data, (*secret)->len); 374*0Sstevel@tonic-gate #else 375*0Sstevel@tonic-gate utils->erasebuffer((*secret)->data, (*secret)->len); 376*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 377*0Sstevel@tonic-gate utils->free(*secret); 378*0Sstevel@tonic-gate *secret = NULL; 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate /* 382*0Sstevel@tonic-gate * Trys to find the prompt with the lookingfor id in the prompt list 383*0Sstevel@tonic-gate * Returns it if found. NULL otherwise 384*0Sstevel@tonic-gate */ 385*0Sstevel@tonic-gate sasl_interact_t *_plug_find_prompt(sasl_interact_t **promptlist, 386*0Sstevel@tonic-gate unsigned int lookingfor) 387*0Sstevel@tonic-gate { 388*0Sstevel@tonic-gate sasl_interact_t *prompt; 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate if (promptlist && *promptlist) { 391*0Sstevel@tonic-gate for (prompt = *promptlist; prompt->id != SASL_CB_LIST_END; ++prompt) { 392*0Sstevel@tonic-gate if (prompt->id==lookingfor) 393*0Sstevel@tonic-gate return prompt; 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate } 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate return NULL; 398*0Sstevel@tonic-gate } 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate /* 401*0Sstevel@tonic-gate * Retrieve the simple string given by the callback id. 402*0Sstevel@tonic-gate */ 403*0Sstevel@tonic-gate int _plug_get_simple(const sasl_utils_t *utils, unsigned int id, int required, 404*0Sstevel@tonic-gate const char **result, sasl_interact_t **prompt_need) 405*0Sstevel@tonic-gate { 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate int ret = SASL_FAIL; 408*0Sstevel@tonic-gate sasl_getsimple_t *simple_cb; 409*0Sstevel@tonic-gate void *simple_context; 410*0Sstevel@tonic-gate sasl_interact_t *prompt; 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate *result = NULL; 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate /* see if we were given the result in the prompt */ 415*0Sstevel@tonic-gate prompt = _plug_find_prompt(prompt_need, id); 416*0Sstevel@tonic-gate if (prompt != NULL) { 417*0Sstevel@tonic-gate /* We prompted, and got.*/ 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate if (required && !prompt->result) { 420*0Sstevel@tonic-gate SETERROR(utils, "Unexpectedly missing a prompt result"); 421*0Sstevel@tonic-gate return SASL_BADPARAM; 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate *result = prompt->result; 425*0Sstevel@tonic-gate return SASL_OK; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* Try to get the callback... */ 429*0Sstevel@tonic-gate ret = utils->getcallback(utils->conn, id, &simple_cb, &simple_context); 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate if (ret == SASL_FAIL && !required) 432*0Sstevel@tonic-gate return SASL_OK; 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate if (ret == SASL_OK && simple_cb) { 435*0Sstevel@tonic-gate ret = simple_cb(simple_context, id, result, NULL); 436*0Sstevel@tonic-gate if (ret != SASL_OK) 437*0Sstevel@tonic-gate return ret; 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate if (required && !*result) { 440*0Sstevel@tonic-gate PARAMERROR(utils); 441*0Sstevel@tonic-gate return SASL_BADPARAM; 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate return ret; 446*0Sstevel@tonic-gate } 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate /* 449*0Sstevel@tonic-gate * Retrieve the user password. 450*0Sstevel@tonic-gate */ 451*0Sstevel@tonic-gate int _plug_get_password(const sasl_utils_t *utils, sasl_secret_t **password, 452*0Sstevel@tonic-gate unsigned int *iscopy, sasl_interact_t **prompt_need) 453*0Sstevel@tonic-gate { 454*0Sstevel@tonic-gate int ret = SASL_FAIL; 455*0Sstevel@tonic-gate sasl_getsecret_t *pass_cb; 456*0Sstevel@tonic-gate void *pass_context; 457*0Sstevel@tonic-gate sasl_interact_t *prompt; 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate *password = NULL; 460*0Sstevel@tonic-gate *iscopy = 0; 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate /* see if we were given the password in the prompt */ 463*0Sstevel@tonic-gate prompt = _plug_find_prompt(prompt_need, SASL_CB_PASS); 464*0Sstevel@tonic-gate if (prompt != NULL) { 465*0Sstevel@tonic-gate /* We prompted, and got.*/ 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate if (!prompt->result) { 468*0Sstevel@tonic-gate SETERROR(utils, "Unexpectedly missing a prompt result"); 469*0Sstevel@tonic-gate return SASL_BADPARAM; 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate /* copy what we got into a secret_t */ 473*0Sstevel@tonic-gate *password = (sasl_secret_t *) utils->malloc(sizeof(sasl_secret_t) + 474*0Sstevel@tonic-gate prompt->len + 1); 475*0Sstevel@tonic-gate if (!*password) { 476*0Sstevel@tonic-gate MEMERROR(utils); 477*0Sstevel@tonic-gate return SASL_NOMEM; 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate (*password)->len=prompt->len; 481*0Sstevel@tonic-gate memcpy((*password)->data, prompt->result, prompt->len); 482*0Sstevel@tonic-gate (*password)->data[(*password)->len]=0; 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate *iscopy = 1; 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate return SASL_OK; 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate /* Try to get the callback... */ 490*0Sstevel@tonic-gate ret = utils->getcallback(utils->conn, SASL_CB_PASS, 491*0Sstevel@tonic-gate &pass_cb, &pass_context); 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate if (ret == SASL_OK && pass_cb) { 494*0Sstevel@tonic-gate ret = pass_cb(utils->conn, pass_context, SASL_CB_PASS, password); 495*0Sstevel@tonic-gate if (ret != SASL_OK) 496*0Sstevel@tonic-gate return ret; 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate if (!*password) { 499*0Sstevel@tonic-gate PARAMERROR(utils); 500*0Sstevel@tonic-gate return SASL_BADPARAM; 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate return ret; 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate /* 508*0Sstevel@tonic-gate * Retrieve the string given by the challenge prompt id. 509*0Sstevel@tonic-gate */ 510*0Sstevel@tonic-gate int _plug_challenge_prompt(const sasl_utils_t *utils, unsigned int id, 511*0Sstevel@tonic-gate const char *challenge, const char *promptstr, 512*0Sstevel@tonic-gate const char **result, sasl_interact_t **prompt_need) 513*0Sstevel@tonic-gate { 514*0Sstevel@tonic-gate int ret = SASL_FAIL; 515*0Sstevel@tonic-gate sasl_chalprompt_t *chalprompt_cb; 516*0Sstevel@tonic-gate void *chalprompt_context; 517*0Sstevel@tonic-gate sasl_interact_t *prompt; 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate *result = NULL; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate /* see if we were given the password in the prompt */ 522*0Sstevel@tonic-gate prompt = _plug_find_prompt(prompt_need, id); 523*0Sstevel@tonic-gate if (prompt != NULL) { 524*0Sstevel@tonic-gate /* We prompted, and got.*/ 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate if (!prompt->result) { 527*0Sstevel@tonic-gate SETERROR(utils, "Unexpectedly missing a prompt result"); 528*0Sstevel@tonic-gate return SASL_BADPARAM; 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate *result = prompt->result; 532*0Sstevel@tonic-gate return SASL_OK; 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /* Try to get the callback... */ 536*0Sstevel@tonic-gate ret = utils->getcallback(utils->conn, id, 537*0Sstevel@tonic-gate &chalprompt_cb, &chalprompt_context); 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate if (ret == SASL_OK && chalprompt_cb) { 540*0Sstevel@tonic-gate ret = chalprompt_cb(chalprompt_context, id, 541*0Sstevel@tonic-gate challenge, promptstr, NULL, result, NULL); 542*0Sstevel@tonic-gate if (ret != SASL_OK) 543*0Sstevel@tonic-gate return ret; 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate if (!*result) { 546*0Sstevel@tonic-gate PARAMERROR(utils); 547*0Sstevel@tonic-gate return SASL_BADPARAM; 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate } 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate return ret; 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate /* 555*0Sstevel@tonic-gate * Retrieve the client realm. 556*0Sstevel@tonic-gate */ 557*0Sstevel@tonic-gate int _plug_get_realm(const sasl_utils_t *utils, const char **availrealms, 558*0Sstevel@tonic-gate const char **realm, sasl_interact_t **prompt_need) 559*0Sstevel@tonic-gate { 560*0Sstevel@tonic-gate int ret = SASL_FAIL; 561*0Sstevel@tonic-gate sasl_getrealm_t *realm_cb; 562*0Sstevel@tonic-gate void *realm_context; 563*0Sstevel@tonic-gate sasl_interact_t *prompt; 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate *realm = NULL; 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate /* see if we were given the result in the prompt */ 568*0Sstevel@tonic-gate prompt = _plug_find_prompt(prompt_need, SASL_CB_GETREALM); 569*0Sstevel@tonic-gate if (prompt != NULL) { 570*0Sstevel@tonic-gate /* We prompted, and got.*/ 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate if (!prompt->result) { 573*0Sstevel@tonic-gate SETERROR(utils, "Unexpectedly missing a prompt result"); 574*0Sstevel@tonic-gate return SASL_BADPARAM; 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate *realm = prompt->result; 578*0Sstevel@tonic-gate return SASL_OK; 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* Try to get the callback... */ 582*0Sstevel@tonic-gate ret = utils->getcallback(utils->conn, SASL_CB_GETREALM, 583*0Sstevel@tonic-gate &realm_cb, &realm_context); 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate if (ret == SASL_OK && realm_cb) { 586*0Sstevel@tonic-gate ret = realm_cb(realm_context, SASL_CB_GETREALM, availrealms, realm); 587*0Sstevel@tonic-gate if (ret != SASL_OK) 588*0Sstevel@tonic-gate return ret; 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate if (!*realm) { 591*0Sstevel@tonic-gate PARAMERROR(utils); 592*0Sstevel@tonic-gate return SASL_BADPARAM; 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate return ret; 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate /* 600*0Sstevel@tonic-gate * Make the requested prompts. (prompt==NULL means we don't want it) 601*0Sstevel@tonic-gate */ 602*0Sstevel@tonic-gate int _plug_make_prompts(const sasl_utils_t *utils, 603*0Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 604*0Sstevel@tonic-gate void **h, 605*0Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 606*0Sstevel@tonic-gate sasl_interact_t **prompts_res, 607*0Sstevel@tonic-gate const char *user_prompt, const char *user_def, 608*0Sstevel@tonic-gate const char *auth_prompt, const char *auth_def, 609*0Sstevel@tonic-gate const char *pass_prompt, const char *pass_def, 610*0Sstevel@tonic-gate const char *echo_chal, 611*0Sstevel@tonic-gate const char *echo_prompt, const char *echo_def, 612*0Sstevel@tonic-gate const char *realm_chal, 613*0Sstevel@tonic-gate const char *realm_prompt, const char *realm_def) 614*0Sstevel@tonic-gate { 615*0Sstevel@tonic-gate int num = 1; 616*0Sstevel@tonic-gate int alloc_size; 617*0Sstevel@tonic-gate sasl_interact_t *prompts; 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate if (user_prompt) num++; 620*0Sstevel@tonic-gate if (auth_prompt) num++; 621*0Sstevel@tonic-gate if (pass_prompt) num++; 622*0Sstevel@tonic-gate if (echo_prompt) num++; 623*0Sstevel@tonic-gate if (realm_prompt) num++; 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate if (num == 1) { 626*0Sstevel@tonic-gate SETERROR( utils, "make_prompts() called with no actual prompts" ); 627*0Sstevel@tonic-gate return SASL_FAIL; 628*0Sstevel@tonic-gate } 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate alloc_size = sizeof(sasl_interact_t)*num; 631*0Sstevel@tonic-gate prompts = utils->malloc(alloc_size); 632*0Sstevel@tonic-gate if (!prompts) { 633*0Sstevel@tonic-gate MEMERROR( utils ); 634*0Sstevel@tonic-gate return SASL_NOMEM; 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate memset(prompts, 0, alloc_size); 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate *prompts_res = prompts; 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate if (user_prompt) { 641*0Sstevel@tonic-gate (prompts)->id = SASL_CB_USER; 642*0Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 643*0Sstevel@tonic-gate (prompts)->challenge = convert_prompt(utils, h, 644*0Sstevel@tonic-gate gettext("Authorization Name")); 645*0Sstevel@tonic-gate #else 646*0Sstevel@tonic-gate (prompts)->challenge = "Authorization Name"; 647*0Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 648*0Sstevel@tonic-gate (prompts)->prompt = user_prompt; 649*0Sstevel@tonic-gate (prompts)->defresult = user_def; 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate prompts++; 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate if (auth_prompt) { 655*0Sstevel@tonic-gate (prompts)->id = SASL_CB_AUTHNAME; 656*0Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 657*0Sstevel@tonic-gate (prompts)->challenge = convert_prompt(utils, h, 658*0Sstevel@tonic-gate gettext( "Authentication Name")); 659*0Sstevel@tonic-gate #else 660*0Sstevel@tonic-gate (prompts)->challenge = "Authentication Name"; 661*0Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 662*0Sstevel@tonic-gate (prompts)->prompt = auth_prompt; 663*0Sstevel@tonic-gate (prompts)->defresult = auth_def; 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate prompts++; 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate if (pass_prompt) { 669*0Sstevel@tonic-gate (prompts)->id = SASL_CB_PASS; 670*0Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 671*0Sstevel@tonic-gate (prompts)->challenge = convert_prompt(utils, h, gettext("Password")); 672*0Sstevel@tonic-gate #else 673*0Sstevel@tonic-gate (prompts)->challenge = "Password"; 674*0Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 675*0Sstevel@tonic-gate (prompts)->prompt = pass_prompt; 676*0Sstevel@tonic-gate (prompts)->defresult = pass_def; 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate prompts++; 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate if (echo_prompt) { 682*0Sstevel@tonic-gate (prompts)->id = SASL_CB_ECHOPROMPT; 683*0Sstevel@tonic-gate (prompts)->challenge = echo_chal; 684*0Sstevel@tonic-gate (prompts)->prompt = echo_prompt; 685*0Sstevel@tonic-gate (prompts)->defresult = echo_def; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate prompts++; 688*0Sstevel@tonic-gate } 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate if (realm_prompt) { 691*0Sstevel@tonic-gate (prompts)->id = SASL_CB_GETREALM; 692*0Sstevel@tonic-gate (prompts)->challenge = realm_chal; 693*0Sstevel@tonic-gate (prompts)->prompt = realm_prompt; 694*0Sstevel@tonic-gate (prompts)->defresult = realm_def; 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate prompts++; 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate /* add the ending one */ 700*0Sstevel@tonic-gate (prompts)->id = SASL_CB_LIST_END; 701*0Sstevel@tonic-gate (prompts)->challenge = NULL; 702*0Sstevel@tonic-gate (prompts)->prompt = NULL; 703*0Sstevel@tonic-gate (prompts)->defresult = NULL; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate return SASL_OK; 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate /* 709*0Sstevel@tonic-gate * Decode and concatenate multiple packets using the given function 710*0Sstevel@tonic-gate * to decode each packet. 711*0Sstevel@tonic-gate */ 712*0Sstevel@tonic-gate int _plug_decode(const sasl_utils_t *utils, 713*0Sstevel@tonic-gate void *context, 714*0Sstevel@tonic-gate const char *input, unsigned inputlen, 715*0Sstevel@tonic-gate char **output, /* output buffer */ 716*0Sstevel@tonic-gate unsigned *outputsize, /* current size of output buffer */ 717*0Sstevel@tonic-gate unsigned *outputlen, /* length of data in output buffer */ 718*0Sstevel@tonic-gate int (*decode_pkt)(void *context, 719*0Sstevel@tonic-gate const char **input, unsigned *inputlen, 720*0Sstevel@tonic-gate char **output, unsigned *outputlen)) 721*0Sstevel@tonic-gate { 722*0Sstevel@tonic-gate char *tmp = NULL; 723*0Sstevel@tonic-gate unsigned tmplen = 0; 724*0Sstevel@tonic-gate int ret; 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate *outputlen = 0; 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate while (inputlen!=0) 729*0Sstevel@tonic-gate { 730*0Sstevel@tonic-gate /* no need to free tmp */ 731*0Sstevel@tonic-gate ret = decode_pkt(context, &input, &inputlen, &tmp, &tmplen); 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate if(ret != SASL_OK) return ret; 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate if (tmp!=NULL) /* if received 2 packets merge them together */ 736*0Sstevel@tonic-gate { 737*0Sstevel@tonic-gate ret = _plug_buf_alloc(utils, output, outputsize, 738*0Sstevel@tonic-gate *outputlen + tmplen + 1); 739*0Sstevel@tonic-gate if(ret != SASL_OK) return ret; 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate memcpy(*output + *outputlen, tmp, tmplen); 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate /* Protect stupid clients */ 744*0Sstevel@tonic-gate *(*output + *outputlen + tmplen) = '\0'; 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate *outputlen+=tmplen; 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate } 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate return SASL_OK; 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate /* returns the realm we should pretend to be in */ 754*0Sstevel@tonic-gate int _plug_parseuser(const sasl_utils_t *utils, 755*0Sstevel@tonic-gate char **user, char **realm, const char *user_realm, 756*0Sstevel@tonic-gate const char *serverFQDN, const char *input) 757*0Sstevel@tonic-gate { 758*0Sstevel@tonic-gate int ret; 759*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 760*0Sstevel@tonic-gate const char *r; 761*0Sstevel@tonic-gate #else 762*0Sstevel@tonic-gate char *r; 763*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate if(!user || !serverFQDN) { 766*0Sstevel@tonic-gate PARAMERROR( utils ); 767*0Sstevel@tonic-gate return SASL_BADPARAM; 768*0Sstevel@tonic-gate } 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate r = strchr(input, '@'); 771*0Sstevel@tonic-gate if (!r) { 772*0Sstevel@tonic-gate /* hmmm, the user didn't specify a realm */ 773*0Sstevel@tonic-gate if(user_realm && user_realm[0]) { 774*0Sstevel@tonic-gate ret = _plug_strdup(utils, user_realm, realm, NULL); 775*0Sstevel@tonic-gate } else { 776*0Sstevel@tonic-gate /* Default to serverFQDN */ 777*0Sstevel@tonic-gate ret = _plug_strdup(utils, serverFQDN, realm, NULL); 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate if (ret == SASL_OK) { 781*0Sstevel@tonic-gate ret = _plug_strdup(utils, input, user, NULL); 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate } else { 784*0Sstevel@tonic-gate r++; 785*0Sstevel@tonic-gate ret = _plug_strdup(utils, r, realm, NULL); 786*0Sstevel@tonic-gate #ifdef _SUN_SDK_ 787*0Sstevel@tonic-gate if (ret == SASL_OK) { 788*0Sstevel@tonic-gate *user = utils->malloc(r - input); 789*0Sstevel@tonic-gate if (*user) { 790*0Sstevel@tonic-gate memcpy(*user, input, r - input - 1); 791*0Sstevel@tonic-gate (*user)[r - input - 1] = '\0'; 792*0Sstevel@tonic-gate } else { 793*0Sstevel@tonic-gate MEMERROR( utils ); 794*0Sstevel@tonic-gate ret = SASL_NOMEM; 795*0Sstevel@tonic-gate } 796*0Sstevel@tonic-gate } 797*0Sstevel@tonic-gate #else 798*0Sstevel@tonic-gate *--r = '\0'; 799*0Sstevel@tonic-gate *user = utils->malloc(r - input + 1); 800*0Sstevel@tonic-gate if (*user) { 801*0Sstevel@tonic-gate strncpy(*user, input, r - input +1); 802*0Sstevel@tonic-gate } else { 803*0Sstevel@tonic-gate MEMERROR( utils ); 804*0Sstevel@tonic-gate ret = SASL_NOMEM; 805*0Sstevel@tonic-gate } 806*0Sstevel@tonic-gate *r = '@'; 807*0Sstevel@tonic-gate #endif /* _SUN_SDK_ */ 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate return ret; 811*0Sstevel@tonic-gate } 812*0Sstevel@tonic-gate 813*0Sstevel@tonic-gate #ifdef _INTEGRATED_SOLARIS_ 814*0Sstevel@tonic-gate int 815*0Sstevel@tonic-gate use_locale(const char *lang_list, int is_client) 816*0Sstevel@tonic-gate { 817*0Sstevel@tonic-gate const char *s; 818*0Sstevel@tonic-gate const char *begin; 819*0Sstevel@tonic-gate const char *end; 820*0Sstevel@tonic-gate const char *i_default = "i-default"; 821*0Sstevel@tonic-gate const int i_default_len = 9; 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate if (lang_list == NULL) 824*0Sstevel@tonic-gate return is_client; 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate begin = lang_list; 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate for (;;) { 829*0Sstevel@tonic-gate /* skip over leading whitespace and commas */ 830*0Sstevel@tonic-gate while (isspace(*begin) || *begin == ',') 831*0Sstevel@tonic-gate begin++; 832*0Sstevel@tonic-gate if (*begin == '\0') 833*0Sstevel@tonic-gate break; 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate /* Find the end of the language tag */ 836*0Sstevel@tonic-gate for (end = begin; end[1] != ',' && end[1] != '\0'; end++) {} 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate for (s = end; isspace(*s); s--) {} 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate if (s == begin && *begin == '*') 841*0Sstevel@tonic-gate return 1; 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate if (s - begin == (i_default_len - 1) && 844*0Sstevel@tonic-gate strncasecmp(begin, i_default, i_default_len) == 0) 845*0Sstevel@tonic-gate return 0; 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate begin = end + 1; 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate return is_client; 851*0Sstevel@tonic-gate } 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate typedef struct prompt_list { 854*0Sstevel@tonic-gate char *prompt; 855*0Sstevel@tonic-gate struct prompt_list *next; 856*0Sstevel@tonic-gate } prompt_list; 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate const char * 859*0Sstevel@tonic-gate convert_prompt(const sasl_utils_t *utils, void **h, const char *s) 860*0Sstevel@tonic-gate { 861*0Sstevel@tonic-gate sasl_getsimple_t *simple_cb; 862*0Sstevel@tonic-gate void *simple_context; 863*0Sstevel@tonic-gate const char *result = NULL; 864*0Sstevel@tonic-gate const char *s_locale; 865*0Sstevel@tonic-gate int ret; 866*0Sstevel@tonic-gate char *buf; 867*0Sstevel@tonic-gate const char *ret_buf; 868*0Sstevel@tonic-gate prompt_list *list; 869*0Sstevel@tonic-gate prompt_list *next; 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate if (utils == NULL || utils->conn == NULL) 872*0Sstevel@tonic-gate return s; 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate if (s == NULL) { 875*0Sstevel@tonic-gate for (list = (prompt_list *)*h; list != NULL; list = next) { 876*0Sstevel@tonic-gate if (list->prompt) 877*0Sstevel@tonic-gate utils->free(list->prompt); 878*0Sstevel@tonic-gate next = list->next; 879*0Sstevel@tonic-gate utils->free(list); 880*0Sstevel@tonic-gate } 881*0Sstevel@tonic-gate *h = NULL; 882*0Sstevel@tonic-gate return NULL; 883*0Sstevel@tonic-gate } 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate ret = utils->getcallback(utils->conn, SASL_CB_LANGUAGE, &simple_cb, 886*0Sstevel@tonic-gate &simple_context); 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate if (ret == SASL_OK && simple_cb) { 889*0Sstevel@tonic-gate ret = simple_cb(simple_context, SASL_CB_LANGUAGE, &result, NULL); 890*0Sstevel@tonic-gate } else 891*0Sstevel@tonic-gate ret = SASL_FAIL; 892*0Sstevel@tonic-gate if (ret == SASL_OK && !use_locale(result, 1)) 893*0Sstevel@tonic-gate return s; 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate s_locale = dgettext(TEXT_DOMAIN, s); 896*0Sstevel@tonic-gate if (s == s_locale) { 897*0Sstevel@tonic-gate return s; 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate 900*0Sstevel@tonic-gate buf = local_to_utf(utils, s_locale); 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gate if (buf != NULL) { 903*0Sstevel@tonic-gate list = utils->malloc(sizeof (prompt_list)); 904*0Sstevel@tonic-gate if (list == NULL) { 905*0Sstevel@tonic-gate utils->free(buf); 906*0Sstevel@tonic-gate buf = NULL; 907*0Sstevel@tonic-gate } else { 908*0Sstevel@tonic-gate list->prompt = buf; 909*0Sstevel@tonic-gate list->next = *h; 910*0Sstevel@tonic-gate *h = list; 911*0Sstevel@tonic-gate } 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate ret_buf = (buf == NULL) ? s : buf; 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate return ret_buf; 917*0Sstevel@tonic-gate } 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate #include <iconv.h> 920*0Sstevel@tonic-gate #include <langinfo.h> 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate /* 923*0Sstevel@tonic-gate * local_to_utf converts a string in the current codeset to utf-8. 924*0Sstevel@tonic-gate * If no codeset is specified, then codeset 646 will be used. 925*0Sstevel@tonic-gate * Upon successful completion, this function will return a non-NULL buffer 926*0Sstevel@tonic-gate * that is allocated by local_to_utf. 927*0Sstevel@tonic-gate * 928*0Sstevel@tonic-gate * If utils is NULL, local_to_utf will use the standard memory allocation 929*0Sstevel@tonic-gate * functions, otherwise the memory functions defined in sasl_utils_t will 930*0Sstevel@tonic-gate * be used. 931*0Sstevel@tonic-gate * 932*0Sstevel@tonic-gate * local_to_utf will return NULL in the case of any error 933*0Sstevel@tonic-gate */ 934*0Sstevel@tonic-gate char * 935*0Sstevel@tonic-gate local_to_utf(const sasl_utils_t *utils, const char *s) 936*0Sstevel@tonic-gate { 937*0Sstevel@tonic-gate const char *code_set = nl_langinfo(CODESET); 938*0Sstevel@tonic-gate iconv_t cd; 939*0Sstevel@tonic-gate char *buf, *tmp; 940*0Sstevel@tonic-gate size_t in_len; 941*0Sstevel@tonic-gate size_t buf_size; 942*0Sstevel@tonic-gate size_t ileft, oleft; 943*0Sstevel@tonic-gate const char *inptr; 944*0Sstevel@tonic-gate char *outptr; 945*0Sstevel@tonic-gate size_t ret; 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate if (s == NULL) 948*0Sstevel@tonic-gate return NULL; 949*0Sstevel@tonic-gate 950*0Sstevel@tonic-gate if (code_set == NULL) 951*0Sstevel@tonic-gate code_set = "646"; 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate if (strcasecmp(code_set, "UTF-8") == 0) { 954*0Sstevel@tonic-gate if (utils == NULL) 955*0Sstevel@tonic-gate buf = strdup(s); 956*0Sstevel@tonic-gate else { 957*0Sstevel@tonic-gate if (_plug_strdup(utils, s, &buf, NULL) != SASL_OK) 958*0Sstevel@tonic-gate buf = NULL; 959*0Sstevel@tonic-gate } 960*0Sstevel@tonic-gate return buf; 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate cd = iconv_open("UTF-8", code_set); 963*0Sstevel@tonic-gate if (cd == (iconv_t)-1) 964*0Sstevel@tonic-gate return NULL; 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate in_len = strlen(s); 967*0Sstevel@tonic-gate buf_size = 4 * (in_len + 1); /* guess */ 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate if (utils == NULL) 970*0Sstevel@tonic-gate buf = malloc(buf_size); 971*0Sstevel@tonic-gate else 972*0Sstevel@tonic-gate buf = utils->malloc(buf_size); 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate if (buf == NULL) { 975*0Sstevel@tonic-gate (void) iconv_close(cd); 976*0Sstevel@tonic-gate return NULL; 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate inptr = s; 979*0Sstevel@tonic-gate ileft = in_len; 980*0Sstevel@tonic-gate outptr = buf; 981*0Sstevel@tonic-gate oleft = buf_size; 982*0Sstevel@tonic-gate for (;;) { 983*0Sstevel@tonic-gate ret = iconv(cd, &inptr, &ileft, &outptr, &oleft); 984*0Sstevel@tonic-gate if (ret == (size_t)(-1)) { 985*0Sstevel@tonic-gate if (errno == E2BIG) { 986*0Sstevel@tonic-gate oleft += buf_size; 987*0Sstevel@tonic-gate buf_size *= 2; 988*0Sstevel@tonic-gate if (utils == NULL) 989*0Sstevel@tonic-gate tmp = realloc(buf, buf_size); 990*0Sstevel@tonic-gate else 991*0Sstevel@tonic-gate tmp = utils->realloc(buf, buf_size); 992*0Sstevel@tonic-gate if (tmp == NULL) { 993*0Sstevel@tonic-gate oleft = (size_t)(-1); 994*0Sstevel@tonic-gate break; 995*0Sstevel@tonic-gate } 996*0Sstevel@tonic-gate outptr = tmp + (outptr-buf); 997*0Sstevel@tonic-gate buf = tmp; 998*0Sstevel@tonic-gate continue; 999*0Sstevel@tonic-gate } 1000*0Sstevel@tonic-gate oleft = (size_t)(-1); 1001*0Sstevel@tonic-gate break; 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate if (inptr == NULL) 1004*0Sstevel@tonic-gate break; 1005*0Sstevel@tonic-gate inptr = NULL; 1006*0Sstevel@tonic-gate ileft = 0; 1007*0Sstevel@tonic-gate } 1008*0Sstevel@tonic-gate if (oleft > 0) { 1009*0Sstevel@tonic-gate *outptr = '\0'; 1010*0Sstevel@tonic-gate } else if (oleft != (size_t)(-1)) { 1011*0Sstevel@tonic-gate if (utils == NULL) 1012*0Sstevel@tonic-gate tmp = realloc(buf, buf_size + 1); 1013*0Sstevel@tonic-gate else 1014*0Sstevel@tonic-gate tmp = utils->realloc(buf, buf_size + 1); 1015*0Sstevel@tonic-gate if (tmp == NULL) { 1016*0Sstevel@tonic-gate oleft = (size_t)(-1); 1017*0Sstevel@tonic-gate } else { 1018*0Sstevel@tonic-gate buf = tmp; 1019*0Sstevel@tonic-gate buf[buf_size] = '\0'; 1020*0Sstevel@tonic-gate } 1021*0Sstevel@tonic-gate } 1022*0Sstevel@tonic-gate if (oleft == (size_t)(-1)) { 1023*0Sstevel@tonic-gate if (utils == NULL) 1024*0Sstevel@tonic-gate free(buf); 1025*0Sstevel@tonic-gate else 1026*0Sstevel@tonic-gate utils->free(buf); 1027*0Sstevel@tonic-gate buf = NULL; 1028*0Sstevel@tonic-gate } 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate (void) iconv_close(cd); 1031*0Sstevel@tonic-gate return buf; 1032*0Sstevel@tonic-gate } 1033*0Sstevel@tonic-gate #endif /* _INTEGRATED_SOLARIS_ */ 1034