2N/A/*
2N/A * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/* Generic SASL plugin utility functions
2N/A * Rob Siemborski
2N/A * $Id: plugin_common.c,v 1.13 2003/02/13 19:56:05 rjs3 Exp $
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
2N/A *
2N/A * Redistribution and use in source and binary forms, with or without
2N/A * modification, are permitted provided that the following conditions
2N/A * are met:
2N/A *
2N/A * 1. Redistributions of source code must retain the above copyright
2N/A * notice, this list of conditions and the following disclaimer.
2N/A *
2N/A * 2. Redistributions in binary form must reproduce the above copyright
2N/A * notice, this list of conditions and the following disclaimer in
2N/A * the documentation and/or other materials provided with the
2N/A * distribution.
2N/A *
2N/A * 3. The name "Carnegie Mellon University" must not be used to
2N/A * endorse or promote products derived from this software without
2N/A * prior written permission. For permission or any other legal
2N/A * details, please contact
2N/A * Office of Technology Transfer
2N/A * Carnegie Mellon University
2N/A * 5000 Forbes Avenue
2N/A * Pittsburgh, PA 15213-3890
2N/A * (412) 268-4387, fax: (412) 268-7395
2N/A * tech-transfer@andrew.cmu.edu
2N/A *
2N/A * 4. Redistributions of any form whatsoever must retain the following
2N/A * acknowledgment:
2N/A * "This product includes software developed by Computing Services
2N/A * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
2N/A *
2N/A * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
2N/A * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
2N/A * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
2N/A * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2N/A * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
2N/A * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
2N/A * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2N/A */
2N/A
2N/A#include <config.h>
2N/A#ifndef macintosh
2N/A#ifdef WIN32
2N/A# include <winsock.h>
2N/A#else
2N/A# include <sys/socket.h>
2N/A# include <netinet/in.h>
2N/A# include <arpa/inet.h>
2N/A# include <netdb.h>
2N/A#endif /* WIN32 */
2N/A#endif /* macintosh */
2N/A#ifdef HAVE_UNISTD_H
2N/A#include <unistd.h>
2N/A#endif
2N/A#include <fcntl.h>
2N/A#include <sasl.h>
2N/A#include <saslutil.h>
2N/A#include <saslplug.h>
2N/A
2N/A#include <errno.h>
2N/A#include <ctype.h>
2N/A
2N/A#ifdef HAVE_INTTYPES_H
2N/A#include <inttypes.h>
2N/A#endif
2N/A
2N/A#include "plugin_common.h"
2N/A
2N/A/* translate IPv4 mapped IPv6 address to IPv4 address */
2N/Astatic void sockaddr_unmapped(
2N/A#ifdef IN6_IS_ADDR_V4MAPPED
2N/A struct sockaddr *sa, socklen_t *len
2N/A#else
2N/A struct sockaddr *sa __attribute__((unused)),
2N/A socklen_t *len __attribute__((unused))
2N/A#endif
2N/A)
2N/A{
2N/A#ifdef IN6_IS_ADDR_V4MAPPED
2N/A struct sockaddr_in6 *sin6;
2N/A struct sockaddr_in *sin4;
2N/A uint32_t addr;
2N/A#ifdef _SUN_SDK_
2N/A in_port_t port;
2N/A#else
2N/A int port;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if (sa->sa_family != AF_INET6)
2N/A return;
2N/A/* LINTED pointer alignment */
2N/A sin6 = (struct sockaddr_in6 *)sa;
2N/A if (!IN6_IS_ADDR_V4MAPPED((&sin6->sin6_addr)))
2N/A return;
2N/A/* LINTED pointer alignment */
2N/A sin4 = (struct sockaddr_in *)sa;
2N/A/* LINTED pointer alignment */
2N/A addr = *(uint32_t *)&sin6->sin6_addr.s6_addr[12];
2N/A port = sin6->sin6_port;
2N/A memset(sin4, 0, sizeof(struct sockaddr_in));
2N/A sin4->sin_addr.s_addr = addr;
2N/A sin4->sin_port = port;
2N/A sin4->sin_family = AF_INET;
2N/A#ifdef HAVE_SOCKADDR_SA_LEN
2N/A sin4->sin_len = sizeof(struct sockaddr_in);
2N/A#endif
2N/A *len = sizeof(struct sockaddr_in);
2N/A#else
2N/A return;
2N/A#endif
2N/A}
2N/A
2N/Aint _plug_ipfromstring(const sasl_utils_t *utils, const char *addr,
2N/A struct sockaddr *out, socklen_t outlen)
2N/A{
2N/A int i, j;
2N/A socklen_t len;
2N/A#ifdef WINNT /* _SUN_SDK_ */
2N/A struct sockaddr_in ss;
2N/A#else
2N/A struct sockaddr_storage ss;
2N/A#endif /* _SUN_SDK_ */
2N/A struct addrinfo hints, *ai = NULL;
2N/A char hbuf[NI_MAXHOST];
2N/A#ifdef _SUN_SDK_
2N/A const char *start, *end, *p;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if(!utils || !addr || !out) {
2N/A if(utils) PARAMERROR( utils );
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A#ifdef _SUN_SDK_
2N/A end = strchr(addr, ']');
2N/A if (end != NULL) {
2N/A /* This an rfc 2732 ipv6 address */
2N/A start = strchr(addr, '[');
2N/A if (start >= end || start == NULL) {
2N/A if(utils) PARAMERROR( utils );
2N/A return SASL_BADPARAM;
2N/A }
2N/A for (i = 0, p = start + 1; p < end; p++) {
2N/A hbuf[i++] = *p;
2N/A if (i >= NI_MAXHOST)
2N/A break;
2N/A }
2N/A p = strchr(end, ':');
2N/A if (p == NULL)
2N/A p = end + 1;
2N/A else
2N/A p = p + 1;
2N/A } else {
2N/A for (i = 0; addr[i] != '\0' && addr[i] != ';'; ) {
2N/A hbuf[i] = addr[i];
2N/A if (++i >= NI_MAXHOST)
2N/A break;
2N/A }
2N/A if (addr[i] == ';')
2N/A p = &addr[i+1];
2N/A else
2N/A p = &addr[i];
2N/A }
2N/A if (i >= NI_MAXHOST) {
2N/A if(utils) PARAMERROR( utils );
2N/A return SASL_BADPARAM;
2N/A }
2N/A hbuf[i] = '\0';
2N/A for (j = 0; p[j] != '\0'; j++)
2N/A if (!isdigit((int)(p[j]))) {
2N/A PARAMERROR( utils );
2N/A return SASL_BADPARAM;
2N/A }
2N/A#else
2N/A /* Parse the address */
2N/A for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
2N/A if (i >= NI_MAXHOST) {
2N/A if(utils) PARAMERROR( utils );
2N/A return SASL_BADPARAM;
2N/A }
2N/A hbuf[i] = addr[i];
2N/A }
2N/A hbuf[i] = '\0';
2N/A
2N/A if (addr[i] == ';')
2N/A i++;
2N/A /* XXX/FIXME: Do we need this check? */
2N/A for (j = i; addr[j] != '\0'; j++)
2N/A if (!isdigit((int)(addr[j]))) {
2N/A PARAMERROR( utils );
2N/A return SASL_BADPARAM;
2N/A }
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A memset(&hints, 0, sizeof(hints));
2N/A hints.ai_family = PF_UNSPEC;
2N/A hints.ai_socktype = SOCK_STREAM;
2N/A hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A if (getaddrinfo(hbuf, p, &hints, &ai) != 0) {
2N/A#else
2N/A if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0) {
2N/A#endif /* _SUN_SDK_ */
2N/A PARAMERROR( utils );
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A len = ai->ai_addrlen;
2N/A#ifdef _SUN_SDK_
2N/A if (len > sizeof(ss))
2N/A return (SASL_BUFOVER);
2N/A#endif /* _SUN_SDK_ */
2N/A memcpy(&ss, ai->ai_addr, len);
2N/A freeaddrinfo(ai);
2N/A sockaddr_unmapped((struct sockaddr *)&ss, &len);
2N/A if (outlen < len) {
2N/A PARAMERROR( utils );
2N/A return SASL_BUFOVER;
2N/A }
2N/A
2N/A memcpy(out, &ss, len);
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/Aint _plug_iovec_to_buf(const sasl_utils_t *utils, const struct iovec *vec,
2N/A unsigned numiov, buffer_info_t **output)
2N/A{
2N/A unsigned i;
2N/A int ret;
2N/A buffer_info_t *out;
2N/A char *pos;
2N/A
2N/A if(!utils || !vec || !output) {
2N/A if(utils) PARAMERROR( utils );
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A if(!(*output)) {
2N/A *output = utils->malloc(sizeof(buffer_info_t));
2N/A if(!*output) {
2N/A MEMERROR(utils);
2N/A return SASL_NOMEM;
2N/A }
2N/A memset(*output,0,sizeof(buffer_info_t));
2N/A }
2N/A
2N/A out = *output;
2N/A
2N/A out->curlen = 0;
2N/A for(i=0; i<numiov; i++)
2N/A out->curlen += vec[i].iov_len;
2N/A
2N/A ret = _plug_buf_alloc(utils, &out->data, &out->reallen, out->curlen);
2N/A
2N/A if(ret != SASL_OK) {
2N/A MEMERROR(utils);
2N/A return SASL_NOMEM;
2N/A }
2N/A
2N/A memset(out->data, 0, out->reallen);
2N/A pos = out->data;
2N/A
2N/A for(i=0; i<numiov; i++) {
2N/A memcpy(pos, vec[i].iov_base, vec[i].iov_len);
2N/A pos += vec[i].iov_len;
2N/A }
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/A/* Basically a conditional call to realloc(), if we need more */
2N/Aint _plug_buf_alloc(const sasl_utils_t *utils, char **rwbuf,
2N/A unsigned *curlen, unsigned newlen)
2N/A{
2N/A if(!utils || !rwbuf || !curlen) {
2N/A PARAMERROR(utils);
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A if(!(*rwbuf)) {
2N/A *rwbuf = utils->malloc(newlen);
2N/A if (*rwbuf == NULL) {
2N/A *curlen = 0;
2N/A MEMERROR(utils);
2N/A return SASL_NOMEM;
2N/A }
2N/A *curlen = newlen;
2N/A } else if(*rwbuf && *curlen < newlen) {
2N/A#ifdef _SUN_SDK_
2N/A unsigned needed = 2*(*curlen);
2N/A#else
2N/A size_t needed = 2*(*curlen);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A while(needed < newlen)
2N/A needed *= 2;
2N/A
2N/A *rwbuf = utils->realloc(*rwbuf, needed);
2N/A if (*rwbuf == NULL) {
2N/A *curlen = 0;
2N/A MEMERROR(utils);
2N/A return SASL_NOMEM;
2N/A }
2N/A *curlen = needed;
2N/A }
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/A/* copy a string */
2N/Aint _plug_strdup(const sasl_utils_t * utils, const char *in,
2N/A char **out, int *outlen)
2N/A{
2N/A#ifdef _SUN_SDK_
2N/A int len;
2N/A#else
2N/A size_t len = strlen(in);
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if(!utils || !in || !out) {
2N/A if(utils) PARAMERROR(utils);
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A#ifdef _SUN_SDK_
2N/A len = strlen(in);
2N/A#endif /* _SUN_SDK_ */
2N/A *out = utils->malloc(len + 1);
2N/A if (!*out) {
2N/A MEMERROR(utils);
2N/A return SASL_NOMEM;
2N/A }
2N/A
2N/A strcpy((char *) *out, in);
2N/A
2N/A if (outlen)
2N/A *outlen = len;
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/Avoid _plug_free_string(const sasl_utils_t *utils, char **str)
2N/A{
2N/A size_t len;
2N/A
2N/A if (!utils || !str || !(*str)) return;
2N/A
2N/A len = strlen(*str);
2N/A
2N/A utils->erasebuffer(*str, len);
2N/A utils->free(*str);
2N/A
2N/A *str=NULL;
2N/A}
2N/A
2N/Avoid _plug_free_secret(const sasl_utils_t *utils, sasl_secret_t **secret)
2N/A{
2N/A if(!utils || !secret || !(*secret)) return;
2N/A
2N/A#ifdef _SUN_SDK_
2N/A utils->erasebuffer((char *)(*secret)->data, (*secret)->len);
2N/A#else
2N/A utils->erasebuffer((*secret)->data, (*secret)->len);
2N/A#endif /* _SUN_SDK_ */
2N/A utils->free(*secret);
2N/A *secret = NULL;
2N/A}
2N/A
2N/A/*
2N/A * Trys to find the prompt with the lookingfor id in the prompt list
2N/A * Returns it if found. NULL otherwise
2N/A */
2N/Asasl_interact_t *_plug_find_prompt(sasl_interact_t **promptlist,
2N/A unsigned int lookingfor)
2N/A{
2N/A sasl_interact_t *prompt;
2N/A
2N/A if (promptlist && *promptlist) {
2N/A for (prompt = *promptlist; prompt->id != SASL_CB_LIST_END; ++prompt) {
2N/A if (prompt->id==lookingfor)
2N/A return prompt;
2N/A }
2N/A }
2N/A
2N/A return NULL;
2N/A}
2N/A
2N/A/*
2N/A * Retrieve the simple string given by the callback id.
2N/A */
2N/Aint _plug_get_simple(const sasl_utils_t *utils, unsigned int id, int required,
2N/A const char **result, sasl_interact_t **prompt_need)
2N/A{
2N/A
2N/A int ret = SASL_FAIL;
2N/A sasl_getsimple_t *simple_cb;
2N/A void *simple_context;
2N/A sasl_interact_t *prompt;
2N/A
2N/A *result = NULL;
2N/A
2N/A /* see if we were given the result in the prompt */
2N/A prompt = _plug_find_prompt(prompt_need, id);
2N/A if (prompt != NULL) {
2N/A /* We prompted, and got.*/
2N/A
2N/A if (required && !prompt->result) {
2N/A SETERROR(utils, "Unexpectedly missing a prompt result");
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A *result = prompt->result;
2N/A return SASL_OK;
2N/A }
2N/A
2N/A /* Try to get the callback... */
2N/A ret = utils->getcallback(utils->conn, id, &simple_cb, &simple_context);
2N/A
2N/A if (ret == SASL_FAIL && !required)
2N/A return SASL_OK;
2N/A
2N/A if (ret == SASL_OK && simple_cb) {
2N/A ret = simple_cb(simple_context, id, result, NULL);
2N/A if (ret != SASL_OK)
2N/A return ret;
2N/A
2N/A if (required && !*result) {
2N/A PARAMERROR(utils);
2N/A return SASL_BADPARAM;
2N/A }
2N/A }
2N/A
2N/A return ret;
2N/A}
2N/A
2N/A/*
2N/A * Retrieve the user password.
2N/A */
2N/Aint _plug_get_password(const sasl_utils_t *utils, sasl_secret_t **password,
2N/A unsigned int *iscopy, sasl_interact_t **prompt_need)
2N/A{
2N/A int ret = SASL_FAIL;
2N/A sasl_getsecret_t *pass_cb;
2N/A void *pass_context;
2N/A sasl_interact_t *prompt;
2N/A
2N/A *password = NULL;
2N/A *iscopy = 0;
2N/A
2N/A /* see if we were given the password in the prompt */
2N/A prompt = _plug_find_prompt(prompt_need, SASL_CB_PASS);
2N/A if (prompt != NULL) {
2N/A /* We prompted, and got.*/
2N/A
2N/A if (!prompt->result) {
2N/A SETERROR(utils, "Unexpectedly missing a prompt result");
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A /* copy what we got into a secret_t */
2N/A *password = (sasl_secret_t *) utils->malloc(sizeof(sasl_secret_t) +
2N/A prompt->len + 1);
2N/A if (!*password) {
2N/A MEMERROR(utils);
2N/A return SASL_NOMEM;
2N/A }
2N/A
2N/A (*password)->len=prompt->len;
2N/A memcpy((*password)->data, prompt->result, prompt->len);
2N/A (*password)->data[(*password)->len]=0;
2N/A
2N/A *iscopy = 1;
2N/A
2N/A return SASL_OK;
2N/A }
2N/A
2N/A /* Try to get the callback... */
2N/A ret = utils->getcallback(utils->conn, SASL_CB_PASS,
2N/A &pass_cb, &pass_context);
2N/A
2N/A if (ret == SASL_OK && pass_cb) {
2N/A ret = pass_cb(utils->conn, pass_context, SASL_CB_PASS, password);
2N/A if (ret != SASL_OK)
2N/A return ret;
2N/A
2N/A if (!*password) {
2N/A PARAMERROR(utils);
2N/A return SASL_BADPARAM;
2N/A }
2N/A }
2N/A
2N/A return ret;
2N/A}
2N/A
2N/A/*
2N/A * Retrieve the string given by the challenge prompt id.
2N/A */
2N/Aint _plug_challenge_prompt(const sasl_utils_t *utils, unsigned int id,
2N/A const char *challenge, const char *promptstr,
2N/A const char **result, sasl_interact_t **prompt_need)
2N/A{
2N/A int ret = SASL_FAIL;
2N/A sasl_chalprompt_t *chalprompt_cb;
2N/A void *chalprompt_context;
2N/A sasl_interact_t *prompt;
2N/A
2N/A *result = NULL;
2N/A
2N/A /* see if we were given the password in the prompt */
2N/A prompt = _plug_find_prompt(prompt_need, id);
2N/A if (prompt != NULL) {
2N/A /* We prompted, and got.*/
2N/A
2N/A if (!prompt->result) {
2N/A SETERROR(utils, "Unexpectedly missing a prompt result");
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A *result = prompt->result;
2N/A return SASL_OK;
2N/A }
2N/A
2N/A /* Try to get the callback... */
2N/A ret = utils->getcallback(utils->conn, id,
2N/A &chalprompt_cb, &chalprompt_context);
2N/A
2N/A if (ret == SASL_OK && chalprompt_cb) {
2N/A ret = chalprompt_cb(chalprompt_context, id,
2N/A challenge, promptstr, NULL, result, NULL);
2N/A if (ret != SASL_OK)
2N/A return ret;
2N/A
2N/A if (!*result) {
2N/A PARAMERROR(utils);
2N/A return SASL_BADPARAM;
2N/A }
2N/A }
2N/A
2N/A return ret;
2N/A}
2N/A
2N/A/*
2N/A * Retrieve the client realm.
2N/A */
2N/Aint _plug_get_realm(const sasl_utils_t *utils, const char **availrealms,
2N/A const char **realm, sasl_interact_t **prompt_need)
2N/A{
2N/A int ret = SASL_FAIL;
2N/A sasl_getrealm_t *realm_cb;
2N/A void *realm_context;
2N/A sasl_interact_t *prompt;
2N/A
2N/A *realm = NULL;
2N/A
2N/A /* see if we were given the result in the prompt */
2N/A prompt = _plug_find_prompt(prompt_need, SASL_CB_GETREALM);
2N/A if (prompt != NULL) {
2N/A /* We prompted, and got.*/
2N/A
2N/A if (!prompt->result) {
2N/A SETERROR(utils, "Unexpectedly missing a prompt result");
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A *realm = prompt->result;
2N/A return SASL_OK;
2N/A }
2N/A
2N/A /* Try to get the callback... */
2N/A ret = utils->getcallback(utils->conn, SASL_CB_GETREALM,
2N/A &realm_cb, &realm_context);
2N/A
2N/A if (ret == SASL_OK && realm_cb) {
2N/A ret = realm_cb(realm_context, SASL_CB_GETREALM, availrealms, realm);
2N/A if (ret != SASL_OK)
2N/A return ret;
2N/A
2N/A if (!*realm) {
2N/A PARAMERROR(utils);
2N/A return SASL_BADPARAM;
2N/A }
2N/A }
2N/A
2N/A return ret;
2N/A}
2N/A
2N/A/*
2N/A * Make the requested prompts. (prompt==NULL means we don't want it)
2N/A */
2N/Aint _plug_make_prompts(const sasl_utils_t *utils,
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A void **h,
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A sasl_interact_t **prompts_res,
2N/A const char *user_prompt, const char *user_def,
2N/A const char *auth_prompt, const char *auth_def,
2N/A const char *pass_prompt, const char *pass_def,
2N/A const char *echo_chal,
2N/A const char *echo_prompt, const char *echo_def,
2N/A const char *realm_chal,
2N/A const char *realm_prompt, const char *realm_def)
2N/A{
2N/A int num = 1;
2N/A int alloc_size;
2N/A sasl_interact_t *prompts;
2N/A
2N/A if (user_prompt) num++;
2N/A if (auth_prompt) num++;
2N/A if (pass_prompt) num++;
2N/A if (echo_prompt) num++;
2N/A if (realm_prompt) num++;
2N/A
2N/A if (num == 1) {
2N/A SETERROR( utils, "make_prompts() called with no actual prompts" );
2N/A return SASL_FAIL;
2N/A }
2N/A
2N/A alloc_size = sizeof(sasl_interact_t)*num;
2N/A prompts = utils->malloc(alloc_size);
2N/A if (!prompts) {
2N/A MEMERROR( utils );
2N/A return SASL_NOMEM;
2N/A }
2N/A memset(prompts, 0, alloc_size);
2N/A
2N/A *prompts_res = prompts;
2N/A
2N/A if (user_prompt) {
2N/A (prompts)->id = SASL_CB_USER;
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A (prompts)->challenge = convert_prompt(utils, h,
2N/A gettext("Authorization Name"));
2N/A#else
2N/A (prompts)->challenge = "Authorization Name";
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A (prompts)->prompt = user_prompt;
2N/A (prompts)->defresult = user_def;
2N/A
2N/A prompts++;
2N/A }
2N/A
2N/A if (auth_prompt) {
2N/A (prompts)->id = SASL_CB_AUTHNAME;
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A (prompts)->challenge = convert_prompt(utils, h,
2N/A gettext( "Authentication Name"));
2N/A#else
2N/A (prompts)->challenge = "Authentication Name";
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A (prompts)->prompt = auth_prompt;
2N/A (prompts)->defresult = auth_def;
2N/A
2N/A prompts++;
2N/A }
2N/A
2N/A if (pass_prompt) {
2N/A (prompts)->id = SASL_CB_PASS;
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/A (prompts)->challenge = convert_prompt(utils, h, gettext("Password"));
2N/A#else
2N/A (prompts)->challenge = "Password";
2N/A#endif /* _INTEGRATED_SOLARIS_ */
2N/A (prompts)->prompt = pass_prompt;
2N/A (prompts)->defresult = pass_def;
2N/A
2N/A prompts++;
2N/A }
2N/A
2N/A if (echo_prompt) {
2N/A (prompts)->id = SASL_CB_ECHOPROMPT;
2N/A (prompts)->challenge = echo_chal;
2N/A (prompts)->prompt = echo_prompt;
2N/A (prompts)->defresult = echo_def;
2N/A
2N/A prompts++;
2N/A }
2N/A
2N/A if (realm_prompt) {
2N/A (prompts)->id = SASL_CB_GETREALM;
2N/A (prompts)->challenge = realm_chal;
2N/A (prompts)->prompt = realm_prompt;
2N/A (prompts)->defresult = realm_def;
2N/A
2N/A prompts++;
2N/A }
2N/A
2N/A /* add the ending one */
2N/A (prompts)->id = SASL_CB_LIST_END;
2N/A (prompts)->challenge = NULL;
2N/A (prompts)->prompt = NULL;
2N/A (prompts)->defresult = NULL;
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/A/*
2N/A * Decode and concatenate multiple packets using the given function
2N/A * to decode each packet.
2N/A */
2N/Aint _plug_decode(const sasl_utils_t *utils,
2N/A void *context,
2N/A const char *input, unsigned inputlen,
2N/A char **output, /* output buffer */
2N/A unsigned *outputsize, /* current size of output buffer */
2N/A unsigned *outputlen, /* length of data in output buffer */
2N/A int (*decode_pkt)(void *context,
2N/A const char **input, unsigned *inputlen,
2N/A char **output, unsigned *outputlen))
2N/A{
2N/A char *tmp = NULL;
2N/A unsigned tmplen = 0;
2N/A int ret;
2N/A
2N/A *outputlen = 0;
2N/A
2N/A while (inputlen!=0)
2N/A {
2N/A /* no need to free tmp */
2N/A ret = decode_pkt(context, &input, &inputlen, &tmp, &tmplen);
2N/A
2N/A if(ret != SASL_OK) return ret;
2N/A
2N/A if (tmp!=NULL) /* if received 2 packets merge them together */
2N/A {
2N/A ret = _plug_buf_alloc(utils, output, outputsize,
2N/A *outputlen + tmplen + 1);
2N/A if(ret != SASL_OK) return ret;
2N/A
2N/A memcpy(*output + *outputlen, tmp, tmplen);
2N/A
2N/A /* Protect stupid clients */
2N/A *(*output + *outputlen + tmplen) = '\0';
2N/A
2N/A *outputlen+=tmplen;
2N/A }
2N/A }
2N/A
2N/A return SASL_OK;
2N/A}
2N/A
2N/A/* returns the realm we should pretend to be in */
2N/Aint _plug_parseuser(const sasl_utils_t *utils,
2N/A char **user, char **realm, const char *user_realm,
2N/A const char *serverFQDN, const char *input)
2N/A{
2N/A int ret;
2N/A#ifdef _SUN_SDK_
2N/A const char *r;
2N/A#else
2N/A char *r;
2N/A#endif /* _SUN_SDK_ */
2N/A
2N/A if(!user || !serverFQDN) {
2N/A PARAMERROR( utils );
2N/A return SASL_BADPARAM;
2N/A }
2N/A
2N/A r = strchr(input, '@');
2N/A if (!r) {
2N/A /* hmmm, the user didn't specify a realm */
2N/A if(user_realm && user_realm[0]) {
2N/A ret = _plug_strdup(utils, user_realm, realm, NULL);
2N/A } else {
2N/A /* Default to serverFQDN */
2N/A ret = _plug_strdup(utils, serverFQDN, realm, NULL);
2N/A }
2N/A
2N/A if (ret == SASL_OK) {
2N/A ret = _plug_strdup(utils, input, user, NULL);
2N/A }
2N/A } else {
2N/A r++;
2N/A ret = _plug_strdup(utils, r, realm, NULL);
2N/A#ifdef _SUN_SDK_
2N/A if (ret == SASL_OK) {
2N/A *user = utils->malloc(r - input);
2N/A if (*user) {
2N/A memcpy(*user, input, r - input - 1);
2N/A (*user)[r - input - 1] = '\0';
2N/A } else {
2N/A MEMERROR( utils );
2N/A ret = SASL_NOMEM;
2N/A }
2N/A }
2N/A#else
2N/A *--r = '\0';
2N/A *user = utils->malloc(r - input + 1);
2N/A if (*user) {
2N/A strncpy(*user, input, r - input +1);
2N/A } else {
2N/A MEMERROR( utils );
2N/A ret = SASL_NOMEM;
2N/A }
2N/A *r = '@';
2N/A#endif /* _SUN_SDK_ */
2N/A }
2N/A
2N/A return ret;
2N/A}
2N/A
2N/A#ifdef _INTEGRATED_SOLARIS_
2N/Aint
2N/Ause_locale(const char *lang_list, int is_client)
2N/A{
2N/A const char *s;
2N/A const char *begin;
2N/A const char *end;
2N/A const char *i_default = "i-default";
2N/A const int i_default_len = 9;
2N/A
2N/A if (lang_list == NULL)
2N/A return is_client;
2N/A
2N/A begin = lang_list;
2N/A
2N/A for (;;) {
2N/A /* skip over leading whitespace and commas */
2N/A while (isspace(*begin) || *begin == ',')
2N/A begin++;
2N/A if (*begin == '\0')
2N/A break;
2N/A
2N/A /* Find the end of the language tag */
2N/A for (end = begin; end[1] != ',' && end[1] != '\0'; end++) {}
2N/A
2N/A for (s = end; isspace(*s); s--) {}
2N/A
2N/A if (s == begin && *begin == '*')
2N/A return 1;
2N/A
2N/A if (s - begin == (i_default_len - 1) &&
2N/A strncasecmp(begin, i_default, i_default_len) == 0)
2N/A return 0;
2N/A
2N/A begin = end + 1;
2N/A }
2N/A
2N/A return is_client;
2N/A}
2N/A
2N/Atypedef struct prompt_list {
2N/A char *prompt;
2N/A struct prompt_list *next;
2N/A} prompt_list;
2N/A
2N/Aconst char *
2N/Aconvert_prompt(const sasl_utils_t *utils, void **h, const char *s)
2N/A{
2N/A sasl_getsimple_t *simple_cb;
2N/A void *simple_context;
2N/A const char *result = NULL;
2N/A const char *s_locale;
2N/A int ret;
2N/A char *buf;
2N/A const char *ret_buf;
2N/A prompt_list *list;
2N/A prompt_list *next;
2N/A
2N/A if (utils == NULL || utils->conn == NULL)
2N/A return s;
2N/A
2N/A if (s == NULL) {
2N/A for (list = (prompt_list *)*h; list != NULL; list = next) {
2N/A if (list->prompt)
2N/A utils->free(list->prompt);
2N/A next = list->next;
2N/A utils->free(list);
2N/A }
2N/A *h = NULL;
2N/A return NULL;
2N/A }
2N/A
2N/A ret = utils->getcallback(utils->conn, SASL_CB_LANGUAGE, &simple_cb,
2N/A &simple_context);
2N/A
2N/A if (ret == SASL_OK && simple_cb) {
2N/A ret = simple_cb(simple_context, SASL_CB_LANGUAGE, &result, NULL);
2N/A } else
2N/A ret = SASL_FAIL;
2N/A if (ret == SASL_OK && !use_locale(result, 1))
2N/A return s;
2N/A
2N/A s_locale = dgettext(TEXT_DOMAIN, s);
2N/A if (s == s_locale) {
2N/A return s;
2N/A }
2N/A
2N/A buf = local_to_utf(utils, s_locale);
2N/A
2N/A if (buf != NULL) {
2N/A list = utils->malloc(sizeof (prompt_list));
2N/A if (list == NULL) {
2N/A utils->free(buf);
2N/A buf = NULL;
2N/A } else {
2N/A list->prompt = buf;
2N/A list->next = *h;
2N/A *h = list;
2N/A }
2N/A }
2N/A
2N/A ret_buf = (buf == NULL) ? s : buf;
2N/A
2N/A return ret_buf;
2N/A}
2N/A
2N/A#include <iconv.h>
2N/A#include <langinfo.h>
2N/A
2N/A/*
2N/A * local_to_utf converts a string in the current codeset to utf-8.
2N/A * If no codeset is specified, then codeset 646 will be used.
2N/A * Upon successful completion, this function will return a non-NULL buffer
2N/A * that is allocated by local_to_utf.
2N/A *
2N/A * If utils is NULL, local_to_utf will use the standard memory allocation
2N/A * functions, otherwise the memory functions defined in sasl_utils_t will
2N/A * be used.
2N/A *
2N/A * local_to_utf will return NULL in the case of any error
2N/A */
2N/Achar *
2N/Alocal_to_utf(const sasl_utils_t *utils, const char *s)
2N/A{
2N/A const char *code_set = nl_langinfo(CODESET);
2N/A iconv_t cd;
2N/A char *buf, *tmp;
2N/A size_t in_len;
2N/A size_t buf_size;
2N/A size_t ileft, oleft;
2N/A char *inptr;
2N/A char *outptr;
2N/A size_t ret;
2N/A
2N/A if (s == NULL)
2N/A return NULL;
2N/A
2N/A if (code_set == NULL)
2N/A code_set = "646";
2N/A
2N/A if (strcasecmp(code_set, "UTF-8") == 0) {
2N/A if (utils == NULL)
2N/A buf = strdup(s);
2N/A else {
2N/A if (_plug_strdup(utils, s, &buf, NULL) != SASL_OK)
2N/A buf = NULL;
2N/A }
2N/A return buf;
2N/A }
2N/A cd = iconv_open("UTF-8", code_set);
2N/A if (cd == (iconv_t)-1)
2N/A return NULL;
2N/A
2N/A in_len = strlen(s);
2N/A buf_size = 4 * (in_len + 1); /* guess */
2N/A
2N/A if (utils == NULL)
2N/A buf = malloc(buf_size);
2N/A else
2N/A buf = utils->malloc(buf_size);
2N/A
2N/A if (buf == NULL) {
2N/A (void) iconv_close(cd);
2N/A return NULL;
2N/A }
2N/A inptr = (char *)s;
2N/A ileft = in_len;
2N/A outptr = buf;
2N/A oleft = buf_size;
2N/A for (;;) {
2N/A ret = iconv(cd, &inptr, &ileft, &outptr, &oleft);
2N/A if (ret == (size_t)(-1)) {
2N/A if (errno == E2BIG) {
2N/A oleft += buf_size;
2N/A buf_size *= 2;
2N/A if (utils == NULL)
2N/A tmp = realloc(buf, buf_size);
2N/A else
2N/A tmp = utils->realloc(buf, buf_size);
2N/A if (tmp == NULL) {
2N/A oleft = (size_t)(-1);
2N/A break;
2N/A }
2N/A outptr = tmp + (outptr-buf);
2N/A buf = tmp;
2N/A continue;
2N/A }
2N/A oleft = (size_t)(-1);
2N/A break;
2N/A }
2N/A if (inptr == NULL)
2N/A break;
2N/A inptr = NULL;
2N/A ileft = 0;
2N/A }
2N/A if (oleft > 0) {
2N/A *outptr = '\0';
2N/A } else if (oleft != (size_t)(-1)) {
2N/A if (utils == NULL)
2N/A tmp = realloc(buf, buf_size + 1);
2N/A else
2N/A tmp = utils->realloc(buf, buf_size + 1);
2N/A if (tmp == NULL) {
2N/A oleft = (size_t)(-1);
2N/A } else {
2N/A buf = tmp;
2N/A buf[buf_size] = '\0';
2N/A }
2N/A }
2N/A if (oleft == (size_t)(-1)) {
2N/A if (utils == NULL)
2N/A free(buf);
2N/A else
2N/A utils->free(buf);
2N/A buf = NULL;
2N/A }
2N/A
2N/A (void) iconv_close(cd);
2N/A return buf;
2N/A}
2N/A#endif /* _INTEGRATED_SOLARIS_ */