Esempio n. 1
0
void init_sasl(void) {
#ifdef ENABLE_SASL_PWDB
    memcached_sasl_pwdb = getenv("MEMCACHED_SASL_PWDB");
    if (memcached_sasl_pwdb == NULL) {
       if (settings.verbose) {
          fprintf(stderr,
                  "INFO: MEMCACHED_SASL_PWDB not specified. "
                  "Internal passwd database disabled\n");
       }
       sasl_callbacks[0].id = SASL_CB_LIST_END;
       sasl_callbacks[0].proc = NULL;
    }
#endif

    memset(my_sasl_hostname, 0, sizeof(my_sasl_hostname));
    if (gethostname(my_sasl_hostname, sizeof(my_sasl_hostname)-1) == -1) {
        if (settings.verbose) {
            fprintf(stderr, "Error discovering hostname for SASL\n");
        }
        my_sasl_hostname[0] = '\0';
    }

    if (sasl_server_init(sasl_callbacks, "memcached") != SASL_OK) {
        fprintf(stderr, "Error initializing sasl.\n");
        exit(EXIT_FAILURE);
    } else {
        if (settings.verbose) {
            fprintf(stderr, "Initialized SASL.\n");
        }
    }
}
Esempio n. 2
0
	virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
		VCString vsChans;
		VCString::const_iterator it;
		sArgs.Split(" ", vsChans, false);

		for (it = vsChans.begin(); it != vsChans.end(); ++it) {
			if (it->StrCmp("saslauthd") || it->StrCmp("auxprop")) {
				method += *it + " ";
			}
			else {
				CUtils::PrintError("Ignoring invalid SASL pwcheck method: " + *it);
				sMessage = "Ignored invalid SASL pwcheck method";
			}
		}
		method.TrimRight();

		if (method.empty()) {
			sMessage = "Need a pwcheck method as argument (saslauthd, auxprop)";
			return false;
		}

		if (sasl_server_init(NULL, NULL) != SASL_OK) {
			sMessage = "SASL Could Not Be Initialized - Halting Startup";
			return false;
		}

		return true;
	}
Esempio n. 3
0
/* 
 * cyrussasl.server_init("appname")
 *
 * appname: the name of this application, from SASL's perspective.
 * 
 * This function does not return any values. On failure, it will throw an 
 * error.
 */
static int cyrussasl_sasl_server_init(lua_State *l)
{
  const char *appname;
  int numargs = lua_gettop(l);
  int err;

  if (numargs != 1) {
    lua_pushstring(l, "usage: cyrussasl.server_init(appname)");
    lua_error(l);
    return 0;
  }

  appname = tostring(l, 1);

  err = sasl_server_init( NULL, /* Global callbacks */
			  appname ); 

  if (err != SASL_OK) {
    lua_pushstring(l, "sasl_server_init failed");
    lua_error(l);
    return 0;
  }

  return 0;
}
Esempio n. 4
0
	virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
		VCString vsArgs;
		VCString::const_iterator it;
		sArgs.Split(" ", vsArgs, false);

		for (it = vsArgs.begin(); it != vsArgs.end(); ++it) {
			if (it->Equals("saslauthd") || it->Equals("auxprop")) {
				m_sMethod += *it + " ";
			} else {
				CUtils::PrintError("Ignoring invalid SASL pwcheck method: " + *it);
				sMessage = "Ignored invalid SASL pwcheck method";
			}
		}

		m_sMethod.TrimRight();

		if (m_sMethod.empty()) {
			sMessage = "Need a pwcheck method as argument (saslauthd, auxprop)";
			return false;
		}

		if (sasl_server_init(NULL, NULL) != SASL_OK) {
			sMessage = "SASL Could Not Be Initialized - Halting Startup";
			return false;
		}

		m_cbs[0].id = SASL_CB_GETOPT;
		m_cbs[0].proc = reinterpret_cast<int(*)()>(CSASLAuthMod::getopt);
		m_cbs[0].context = this;
		m_cbs[1].id = SASL_CB_LIST_END;
		m_cbs[1].proc = NULL;
		m_cbs[1].context = NULL;

		return true;
	}
Esempio n. 5
0
EXPORTED void global_sasl_init(int client, int server, const sasl_callback_t *callbacks)
{
    static int called_already = 0;

    assert(client || server);
    assert(!called_already);

    called_already = 1;

    /* set the SASL allocation functions */
    sasl_set_alloc((sasl_malloc_t *) &xmalloc,
                   (sasl_calloc_t *) &xcalloc,
                   (sasl_realloc_t *) &xrealloc,
                   (sasl_free_t *) &free);

    /* set the SASL mutex functions */
    sasl_set_mutex((sasl_mutex_alloc_t *) &cyrus_mutex_alloc,
                   (sasl_mutex_lock_t *) &cyrus_mutex_lock,
                   (sasl_mutex_unlock_t *) &cyrus_mutex_unlock,
                   (sasl_mutex_free_t *) &cyrus_mutex_free);

    if(client && sasl_client_init(callbacks)) {
        fatal("could not init sasl (client)", EC_SOFTWARE);
    }

    if(server && sasl_server_init(callbacks, "Cyrus")) {
        fatal("could not init sasl (server)", EC_SOFTWARE);
    }
}
virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitelist)
{
    virNetSASLContextPtr ctxt;
    int err;

    err = sasl_server_init(NULL, "libvirt");
    if (err != SASL_OK) {
        virNetError(VIR_ERR_AUTH_FAILED,
                    _("failed to initialize SASL library: %d (%s)"),
                    err, sasl_errstring(err, NULL, NULL));
        return NULL;
    }

    if (VIR_ALLOC(ctxt) < 0) {
        virReportOOMError();
        return NULL;
    }

    if (virMutexInit(&ctxt->lock) < 0) {
        virNetError(VIR_ERR_INTERNAL_ERROR, "%s",
                    _("Failed to initialized mutex"));
        VIR_FREE(ctxt);
        return NULL;
    }

    ctxt->usernameWhitelist = usernameWhitelist;
    ctxt->refs = 1;

    return ctxt;
}
Esempio n. 7
0
static svn_error_t *initialize(void *baton, apr_pool_t *pool)
{
  int result;
  SVN_ERR(svn_ra_svn__sasl_common_init(pool));

  /* The second parameter tells SASL to look for a configuration file
     named subversion.conf. */
  result = sasl_server_init(callbacks, SVN_RA_SVN_SASL_NAME);
  if (result != SASL_OK)
    {
      svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                          sasl_errstring(result, NULL, NULL));
      return svn_error_quick_wrap(err,
                                  _("Could not initialize the SASL library"));
    }
  return SVN_NO_ERROR;
}
Esempio n. 8
0
bool pni_init_server(pn_transport_t* transport)
{
  pni_sasl_t *sasl = transport->sasl;
  int result;
  sasl_conn_t *cyrus_conn = NULL;
  do {
    if (sasl->config_dir) {
        result = sasl_set_path(SASL_PATH_TYPE_CONFIG, sasl->config_dir);
        if (result!=SASL_OK) break;
    }

    result = sasl_server_init(NULL, sasl->config_name ? sasl->config_name : "proton-server");
    if (result!=SASL_OK) break;

    result = sasl_server_new(amqp_service, NULL, NULL, NULL, NULL, NULL, 0, &cyrus_conn);
    if (result!=SASL_OK) break;
    sasl->impl_context = cyrus_conn;

    sasl_security_properties_t secprops = {0};
    secprops.security_flags =
      ( sasl->allow_insecure_mechs ? 0 : SASL_SEC_NOPLAINTEXT ) |
      ( transport->auth_required ? SASL_SEC_NOANONYMOUS : 0 ) ;
    secprops.min_ssf = 0;
    secprops.max_ssf = 2048;
    secprops.maxbufsize = PN_SASL_MAX_BUFFSIZE;

    result = sasl_setprop(cyrus_conn, SASL_SEC_PROPS, &secprops);
    if (result!=SASL_OK) break;

    sasl_ssf_t ssf = sasl->external_ssf;
    result = sasl_setprop(cyrus_conn, SASL_SSF_EXTERNAL, &ssf);
    if (result!=SASL_OK) break;

    const char *extid = sasl->external_auth;
    if (extid) {
    result = sasl_setprop(cyrus_conn, SASL_AUTH_EXTERNAL, extid);
    }
  } while (false);
  cyrus_conn = (sasl_conn_t*) sasl->impl_context;
  return pni_check_sasl_result(cyrus_conn, result, transport);
}
Esempio n. 9
0
	bool serverStart(const QString &realm, QStringList *mechlist, const QString &name)
	{
		resetState();

		g->appname = name;
		if(!g->server_init) {
			sasl_server_init(NULL, QFile::encodeName(g->appname));
			g->server_init = true;
		}

		callbacks = new sasl_callback_t[2];

		callbacks[0].id = SASL_CB_PROXY_POLICY;
		callbacks[0].proc = (int(*)())scb_checkauth;
		callbacks[0].context = this;

		callbacks[1].id = SASL_CB_LIST_END;
		callbacks[1].proc = 0;
		callbacks[1].context = 0;

		int r = sasl_server_new(service.toLatin1().data(), host.toLatin1().data(), realm.toLatin1().data(), localAddr.isEmpty() ? 0 : localAddr.toLatin1().data(), remoteAddr.isEmpty() ? 0 : remoteAddr.toLatin1().data(), callbacks, 0, &con);
		if(r != SASL_OK) {
			err = saslErrorCond(r);
			return false;
		}

		if(!setsecprops())
			return false;

		const char *ml;
		r = sasl_listmech(con, 0, NULL, " ", NULL, &ml, 0, 0);
		if(r != SASL_OK)
			return false;
		*mechlist = QString(ml).split(' ', QString::SkipEmptyParts);
		servermode = true;
		step = 0;
		ca_done = false;
		ca_skip = false;
		return true;
	}
Esempio n. 10
0
virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitelist)
{
    virNetSASLContextPtr ctxt;
    int err;

    if (virNetSASLContextInitialize() < 0)
        return NULL;

    err = sasl_server_init(NULL, "libvirt");
    if (err != SASL_OK) {
        virReportError(VIR_ERR_AUTH_FAILED,
                       _("failed to initialize SASL library: %d (%s)"),
                       err, sasl_errstring(err, NULL, NULL));
        return NULL;
    }

    if (!(ctxt = virObjectLockableNew(virNetSASLContextClass)))
        return NULL;

    ctxt->usernameWhitelist = usernameWhitelist;

    return ctxt;
}
Esempio n. 11
0
DWORD
VmDirSASLInit(
    VOID
    )
{
    DWORD       dwError = 0;

    static sasl_callback_t saslServerCB[] =
    {
        { SASL_CB_LOG, (int (*)(void))_VmDirSASLLog, NULL },
        { SASL_CB_GETPATH, (int (*)(void)) _VmDirSASL2PATH, &g_pszSASL2Path },
        { SASL_CB_LIST_END, NULL, NULL }
    };

    dwError = VmDirSASL2PATH(&g_pszSASL2Path);
    BAIL_ON_VMDIR_ERROR(dwError);

    // provide SASL mutex functions
    sasl_set_mutex( _VmDirSASLMutexNew,
                    _VmDirSASLMutexLock,
                    _VmDirSASLMutexUnlock,
                    _VmDirSASLMutexDispose);

    dwError = sasl_server_init( saslServerCB, "vmdird");
    BAIL_ON_SASL_ERROR(dwError);

cleanup:

    return dwError;

error:

    VMDIR_SAFE_FREE_MEMORY(g_pszSASL2Path);
sasl_error:

    goto cleanup;
}
Esempio n. 12
0
int
auth_cyrus_sasl_server(auth_instance *ablock, uschar *data)
{
auth_cyrus_sasl_options_block *ob =
  (auth_cyrus_sasl_options_block *)(ablock->options_block);
uschar *output, *out2, *input, *clear, *hname;
uschar *debug = NULL;   /* Stops compiler complaining */
sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}};
sasl_conn_t *conn;
int rc, firsttime=1, clen;
unsigned int inlen, outlen;

input=data;
inlen=Ustrlen(data);

HDEBUG(D_auth) debug=string_copy(data);

hname=expand_string(ob->server_hostname);
if(hname == NULL)
  {
  auth_defer_msg = expand_string_message;
  return DEFER;
  }

if(inlen)
  {
  clen=auth_b64decode(input, &clear);
  if(clen < 0)
    {
    return BAD64;
    }
  input=clear;
  inlen=clen;
  }

rc=sasl_server_init(cbs, "exim");
if (rc != SASL_OK)
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL library";
  return DEFER;
  }

rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL,
  NULL, NULL, 0, &conn);

if( rc != SASL_OK )
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL connection";
  sasl_done();
  return DEFER;
  }

rc=SASL_CONTINUE;

while(rc==SASL_CONTINUE)
  {
  if(firsttime)
    {
    firsttime=0;
    HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug);
    rc=sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen,
           (const char **)(&output), &outlen);
    }
  else
    {
    /* make sure that we have a null-terminated string */
    out2=store_get(outlen+1);
    memcpy(out2,output,outlen);
    out2[outlen]='\0';
    if((rc=auth_get_data(&input, out2, outlen))!=OK)
      {
      /* we couldn't get the data, so free up the library before
       * returning whatever error we get */
      sasl_dispose(&conn);
      sasl_done();
      return rc;
      }
    inlen=Ustrlen(input);

    HDEBUG(D_auth) debug=string_copy(input);
    if(inlen)
      {
      clen=auth_b64decode(input, &clear);
      if(clen < 0)
       {
        sasl_dispose(&conn);
        sasl_done();
       return BAD64;
       }
      input=clear;
      inlen=clen;
      }

    HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug);
    rc=sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen);
    }
  if(rc==SASL_BADPROT)
    {
    sasl_dispose(&conn);
    sasl_done();
    return UNEXPECTED;
    }
  else if( rc==SASL_FAIL     || rc==SASL_BUFOVER
       || rc==SASL_BADMAC   || rc==SASL_BADAUTH
       || rc==SASL_NOAUTHZ  || rc==SASL_ENCRYPT
       || rc==SASL_EXPIRED  || rc==SASL_DISABLED
       || rc==SASL_NOUSER   )
    {
    /* these are considered permanent failure codes */
    HDEBUG(D_auth)
      debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
    log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
       "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
       sasl_errstring(rc, NULL, NULL));
    sasl_dispose(&conn);
    sasl_done();
    return FAIL;
    }
  else if(rc==SASL_NOMECH)
    {
    /* this is a temporary failure, because the mechanism is not
     * available for this user. If it wasn't available at all, we
     * shouldn't have got here in the first place...
     */
    HDEBUG(D_auth)
      debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
    auth_defer_msg =
        string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech);
    sasl_dispose(&conn);
    sasl_done();
    return DEFER;
    }
  else if(!(rc==SASL_OK || rc==SASL_CONTINUE))
    {
    /* Anything else is a temporary failure, and we'll let SASL print out
     * the error string for us
     */
    HDEBUG(D_auth)
      debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
    auth_defer_msg =
        string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL));
    sasl_dispose(&conn);
    sasl_done();
    return DEFER;
    }
  else if(rc==SASL_OK)
    {
    /* Get the username and copy it into $auth1 and $1. The former is now the
    preferred variable; the latter is the original variable. */
    rc = sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2));
    auth_vars[0] = expand_nstring[1] = string_copy(out2);
    expand_nlength[1] = Ustrlen(expand_nstring[1]);
    expand_nmax = 1;

    HDEBUG(D_auth)
      debug_printf("Cyrus SASL %s authentication succeeded for %s\n", ob->server_mech, out2);
    /* close down the connection, freeing up library's memory */
    sasl_dispose(&conn);
    sasl_done();

    /* Expand server_condition as an authorization check */
    return auth_check_serv_cond(ablock);
    }
  }
/* NOTREACHED */
return 0;  /* Stop compiler complaints */
}
int
main(int argc, char *argv[])
{
	char line[8192];
	char *username, *password;
#if SASL_VERSION_MAJOR < 2
	const char *errstr;
#endif

	int rc;
        sasl_conn_t *conn = NULL;

	/* make standard output line buffered */
	setvbuf(stdout, NULL, _IOLBF, 0);

	rc = sasl_server_init( NULL, APP_NAME_SASL );

	if ( rc != SASL_OK ) {
		fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL ));
		fprintf( stdout, "ERR\n" );
		return 1;
	}

	#if SASL_VERSION_MAJOR < 2
	rc = sasl_server_new( APP_NAME_SASL, NULL, NULL, NULL, 0, &conn );
	#else
	rc = sasl_server_new( APP_NAME_SASL, NULL, NULL, NULL, NULL, NULL, 0, &conn );
	#endif

	if ( rc != SASL_OK ) {
		fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL ));
		fprintf( stdout, "ERR\n" );
		return 1;
	}

	while ( fgets( line, sizeof( line ), stdin )) {
		username = &line[0];
		password = strchr( line, '\n' );
		if ( !password) {
			fprintf( stderr, "authenticator: Unexpected input '%s'\n", line );
			fprintf( stdout, "ERR\n" );
			continue;
		}
		*password = '******';
		password = strchr ( line, ' ' );
		if ( !password) {
			fprintf( stderr, "authenticator: Unexpected input '%s'\n", line );
			fprintf( stdout, "ERR\n" );
			continue;
		}
		*password++ = '\0';

		rfc1738_unescape(username);
		rfc1738_unescape(password);

		#if SASL_VERSION_MAJOR < 2
		rc = sasl_checkpass(conn, username, strlen(username), password, strlen(password), &errstr);
		#else
		rc = sasl_checkpass(conn, username, strlen(username), password, strlen(password));
		#endif

		if ( rc != SASL_OK ) {
			#if SASL_VERSION_MAJOR < 2
			if ( errstr ) {
				fprintf( stderr, "errstr %s\n", errstr );
			}
			if ( rc != SASL_BADAUTH ) {
				fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL ));
			}
			#endif
			fprintf( stdout, "ERR\n" );
		}
		else {
			fprintf( stdout, "OK\n" );
		}

	}

        sasl_dispose( &conn );
        sasl_done();

	return 0;
}
Esempio n. 14
0
int main(int argc, char *argv[])
{
    int c;
    char *port = "12345";
    char *service = "rcmd";
    char *hostname = NULL;
    int *l, maxfd=0;
    int r, i;
    sasl_conn_t *conn;
    int cb_flag = 0;

    while ((c = getopt(argc, argv, "Cch:p:s:m:")) != EOF) {
	switch(c) {
	case 'C':
	    cb_flag = 2;        /* channel bindings are critical */
	    break;

	case 'c':
	    cb_flag = 1;        /* channel bindings are present */
	    break;

	case 'h':
	    hostname = optarg;
	    break;

	case 'p':
	    port = optarg;
	    break;

	case 's':
	    service = optarg;
	    break;

	case 'm':
	    mech = optarg;
	    break;

	default:
	    usage();
	    break;
	}
    }

    /* initialize the sasl library */
    r = sasl_server_init(NULL, "sample");
    if (r != SASL_OK) saslfail(r, "initializing libsasl");

    /* get a listening socket */
    if ((l = listensock(port, PF_UNSPEC)) == NULL) {
	saslfail(SASL_FAIL, "allocating listensock");
    }

    for (i = 1; i <= l[0]; i++) {
       if (l[i] > maxfd)
           maxfd = l[i];
    }

    for (;;) {
	char localaddr[NI_MAXHOST | NI_MAXSERV],
	     remoteaddr[NI_MAXHOST | NI_MAXSERV];
	char myhostname[1024+1];
	char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
	struct sockaddr_storage local_ip, remote_ip;
	int niflags, error;
	socklen_t salen;
	int nfds, fd = -1;
	FILE *in, *out;
	fd_set readfds;
	sasl_channel_binding_t cb;

	FD_ZERO(&readfds);
	for (i = 1; i <= l[0]; i++)
	    FD_SET(l[i], &readfds);

	nfds = select(maxfd + 1, &readfds, 0, 0, 0);
	if (nfds <= 0) {
	    if (nfds < 0 && errno != EINTR)
		perror("select");
	    continue;
	}

       for (i = 1; i <= l[0]; i++) 
           if (FD_ISSET(l[i], &readfds)) {
               fd = accept(l[i], NULL, NULL);
               break;
           }

	if (fd < 0) {
	    if (errno != EINTR)
		perror("accept");
	    continue;
	}

	printf("accepted new connection\n");

	/* set ip addresses */
	salen = sizeof(local_ip);
	if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
	    perror("getsockname");
	}
	niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
#ifdef NI_WITHSCOPEID
	if (((struct sockaddr *)&local_ip)->sa_family == AF_INET6)
	    niflags |= NI_WITHSCOPEID;
#endif
	error = getnameinfo((struct sockaddr *)&local_ip, salen, hbuf,
			    sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
	if (error != 0) {
	    fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
	    strcpy(hbuf, "unknown");
	    strcpy(pbuf, "unknown");
	}
        snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);

	salen = sizeof(remote_ip);
	if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
	    perror("getpeername");
	}

	niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
#ifdef NI_WITHSCOPEID
	if (((struct sockaddr *)&remote_ip)->sa_family == AF_INET6)
	    niflags |= NI_WITHSCOPEID;
#endif
	error = getnameinfo((struct sockaddr *)&remote_ip, salen, hbuf,
			    sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
	if (error != 0) {
	    fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
	    strcpy(hbuf, "unknown");
	    strcpy(pbuf, "unknown");
	}
	snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);

	if (hostname == NULL) {
	    r = gethostname(myhostname, sizeof(myhostname)-1);
	    if(r == -1) saslfail(r, "getting hostname");
	    hostname = myhostname;
	}

	r = sasl_server_new(service, hostname, NULL, localaddr, remoteaddr,
			    NULL, 0, &conn);
	if (r != SASL_OK) saslfail(r, "allocating connection state");

	cb.name = "sasl-sample";
	cb.critical = cb_flag > 1;
	cb.data = "this is a test of channel binding";
	cb.len = strlen(cb.data);

	if (cb_flag) {
	    sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
	}

	/* set external properties here
	sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */

	/* set required security properties here
	sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */

	in = fdopen(fd, "r");
	out = fdopen(fd, "w");

	r = mysasl_negotiate(in, out, conn);
	if (r == SASL_OK) {
	    /* send/receive data */


	}

	printf("closing connection\n");
	fclose(in);
	fclose(out);
	close(fd);
	sasl_dispose(&conn);
    }

    sasl_done();
}
int
main(int argc, char **argv)
{
	const char *user, *realm, *passwd, *service, *mechs, **globals, *err;
	int c, ret;
	sasl_callback_t callbacks[] = {
		{SASL_CB_GETOPT, my_getopt, NULL},
		{SASL_CB_LIST_END},
	};
	sasl_conn_t *connection;
	char hostname[512];
	char fulluser[512]; /* XXX: may overflow */

	user = realm = passwd = service = "";
	strcpy(hostname, "localhost");
	gethostname(hostname, sizeof(hostname));

	while ((c = getopt(argc, argv, "u:r:p:s:h:12v")) != -1) {
		switch (c) {
		case 'u':
			user = optarg;
			break;
		case 'r':
			realm = optarg;
			break;
		case 'p':
			passwd = optarg;
			break;
		case 's':
			service = optarg;
			break;
		case 'h':
			strncpy(hostname, optarg, sizeof(hostname) - 1);
			hostname[sizeof(hostname) - 1] = '\0';
			break;
		case '1':
			main_requested_sasl_version = 1;
			break;
		case '2':
			main_requested_sasl_version = 2;
			break;
		case 'v':
			main_verbose++;
			break;
		default:
			printf("Usage: %s [-v] [-1] [-2] "
			       "[-h hostname] "
			       "[-u user] "
			       "[-r realm] "
			       "[-p password] "
			       "[-s service] "
			       "\n", argv[0]);
			return 2;
			break;
		}
	}
	if ((strlen(user) == 0) || (strlen(passwd) == 0)) {
		printf("Usage: %s [-v] [-1] [-2] "
		       "[-h hostname] "
		       "[-u user] "
		       "[-r realm] "
		       "[-p password] "
		       "[-s service] "
		       "\n", argv[0]);
		return 2;
	}
	if (realm && (strlen(realm) > 0)) {
		sprintf(fulluser, "%s@%s", user, realm);
	} else {
		sprintf(fulluser, "%s", user);
	}

	ret = sasl_server_init(callbacks,
			       strlen(service) ? service : "sasl-checkpass");
	if (ret != SASL_OK) {
		fprintf(stderr, "Error in sasl_server_init(): %s\n",
			sasl_errstring(ret, NULL, NULL));
	}

	connection = NULL;
	ret = sasl_server_new(strlen(service) ? service : "sasl-checkpass",
			      hostname,
			      NULL,
#ifdef SASL2
			      NULL,
			      NULL,
#endif
			      callbacks,
			      0,
			      &connection);
	if (ret != SASL_OK) {
		fprintf(stderr, "Error in sasl_server_new(): %s\n",
			sasl_errstring(ret, NULL, NULL));
	}

	err = NULL;
	ret = sasl_checkpass(connection,
			     fulluser, strlen(fulluser),
			     passwd, strlen(passwd)
#ifndef SASL2
			     , &err
#endif
			     );
	switch (ret) {
	case SASL_OK:
		printf("OK\n");
		break;
	default:
		printf("NO: %d", ret);
		switch (ret) {
		case SASL_FAIL:
			err = "generic failure";
			break;
		case SASL_BADAUTH:
			err = "authentication failure";
			break;
		default:
			err = NULL;
			break;
		}
		if (err) {
			printf(" (%s)", err);
		}
		printf("\n");
		break;
	}
	return ret;
}
Esempio n. 16
0
void
auth_cyrus_sasl_init(auth_instance *ablock)
{
auth_cyrus_sasl_options_block *ob =
  (auth_cyrus_sasl_options_block *)(ablock->options_block);
const uschar *list, *listptr, *buffer;
int rc, i;
unsigned int len;
uschar *rs_point, *expanded_hostname;
char *realm_expanded;

sasl_conn_t *conn;
sasl_callback_t cbs[] = {
  {SASL_CB_GETOPT, NULL, NULL },
  {SASL_CB_LIST_END, NULL, NULL}};

/* default the mechanism to our "public name" */
if (ob->server_mech == NULL)
  ob->server_mech = string_copy(ablock->public_name);

expanded_hostname = expand_string(ob->server_hostname);
if (expanded_hostname == NULL)
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "couldn't expand server_hostname [%s]: %s",
      ablock->name, ob->server_hostname, expand_string_message);

realm_expanded = NULL;
if (ob->server_realm != NULL) {
  realm_expanded = CS expand_string(ob->server_realm);
  if (realm_expanded == NULL)
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
        "couldn't expand server_realm [%s]: %s",
        ablock->name, ob->server_realm, expand_string_message);
}

/* we're going to initialise the library to check that there is an
 * authenticator of type whatever mechanism we're using
 */

cbs[0].proc = (int(*)(void)) &mysasl_config;
cbs[0].context = ob->server_mech;

if ((rc = sasl_server_init(cbs, "exim")) != SASL_OK )
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "couldn't initialise Cyrus SASL library.", ablock->name);

if ((rc = sasl_server_new(CS ob->server_service, CS expanded_hostname,
                   realm_expanded, NULL, NULL, NULL, 0, &conn)) != SASL_OK )
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "couldn't initialise Cyrus SASL server connection.", ablock->name);

if ((rc = sasl_listmech(conn, NULL, "", ":", "", (const char **)&list, &len, &i)) != SASL_OK )
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "couldn't get Cyrus SASL mechanism list.", ablock->name);

i = ':';
listptr = list;

HDEBUG(D_auth)
  {
  debug_printf("Initialised Cyrus SASL service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n",
      ob->server_service, expanded_hostname, realm_expanded);
  debug_printf("Cyrus SASL knows mechanisms: %s\n", list);
  }

/* the store_get / store_reset mechanism is hierarchical
 * the hierarchy is stored for us behind our back. This point
 * creates a hierarchy point for this function.
 */
rs_point = store_get(0);

/* loop until either we get to the end of the list, or we match the
 * public name of this authenticator
 */
while ( ( buffer = string_nextinlist(&listptr, &i, NULL, 0) ) &&
       strcmpic(buffer,ob->server_mech) );

if (!buffer)
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
      "Cyrus SASL doesn't know about mechanism %s.", ablock->name, ob->server_mech);

store_reset(rs_point);

HDEBUG(D_auth) debug_printf("Cyrus SASL driver %s: %s initialised\n", ablock->name, ablock->public_name);

/* make sure that if we get here then we're allowed to advertise. */
ablock->server = TRUE;

sasl_dispose(&conn);
sasl_done();
}
Esempio n. 17
0
File: main.c Progetto: Zabrane/SPOCP
int
main(int argc, char **argv)
{
	int             debug = 0, conftest = 0, nodaemon = 0;
	int             i = 0;
	unsigned int    clilen;
	struct sockaddr_in cliaddr;
	struct timeval  start, end;
	char           *cnfg = DEF_CNFG;
	char		localhost[MAXNAMLEN + 1], path[MAXNAMLEN + 1];
	FILE           *pidfp;
	octet_t         oct;
	ruleset_t      *rs;

	/*
	 * Who am I running as ? 
	 */

	uname(&myname);

	/*
	 * spocp_err = 0 ;
	 */

	memset(&srv, 0, sizeof(srv_t));

	pthread_mutex_init(&(srv.mutex), NULL);
	pthread_mutex_init(&(srv.mlock), NULL);

	gethostname(localhost, MAXNAMLEN);
#ifdef HAVE_GETDOMAINNAME
	getdomainname(path, MAXNAMLEN);
#else
	{
		char *pos;
		if(pos = strstr(localhost, ".")) strncpy(path, pos+1, MAXNAMLEN);
		else strcpy(path, "");
	}
#endif

	if (0)
		printf("Domain: %s\n", path);

	srv.hostname = Strdup(localhost);

	/*
	 * truncating input strings to reasonable length
	 */
	for (i = 0; i < argc; i++)
		if (strlen(argv[i]) > 512)
			argv[i][512] = '\0';

	while ((i = getopt(argc, argv, "Dhrtf:d:")) != EOF) {
		switch (i) {

		case 'D':
			nodaemon = 1;
			break;

		case 'f':
			cnfg = Strdup(optarg);
			break;

		case 'd':
			debug = atoi(optarg);
			if (debug < 0)
				debug = 0;
			break;

		case 't':
			conftest = 1;
			break;

		case 'r':
			srv.readonly = 1;

		case 'h':
		default:
			fprintf(stderr, "Usage: %s [-t] ", argv[0]);
			fprintf(stderr, "[-f configfile] ");
			fprintf(stderr, "[-D] [-d debuglevel]\n");
			exit(0);
		}
	}

	srv.root = ruleset_new(0);

	if (srv_init(&srv, cnfg) < 0)
		exit(1);

	if (srv.port && srv.uds) {
		fprintf(stderr,
			"Sorry are not allowed to listen on both a unix domain socket and a port\n");
		exit(1);
	}

	if (srv.logfile)
		spocp_open_log(srv.logfile, debug);
	else if (debug)
		spocp_open_log(0, debug);

	if (srv.name){
		localcontext = (char *) Calloc(strlen(srv.name) + strlen("//") + 1,
				       sizeof(char));

		/* Flawfinder: ignore */
		sprintf(localcontext, "//%s", srv.name);		
	}
	else {
		localcontext = (char *) Calloc(strlen(localhost) + strlen("//") + 1,
				       sizeof(char));

		/* Flawfinder: ignore */
		sprintf(localcontext, "//%s", localhost);
	}

	/*
	 * where I put the access rules for access to this server and its
	 * rules 
	 */
	snprintf(path, MAXNAMLEN, "%s/server", localcontext);
	oct_assign(&oct, path);
	if ((rs = ruleset_create(&oct, srv.root)) == 0)
		exit(1);

	rs->db = db_new();

	/*
	 * access rules for operations 
	 */
	snprintf(path, MAXNAMLEN, "%s/operation", localcontext);
	oct_assign(&oct, path);
	if ((rs = ruleset_create(&oct, srv.root)) == 0)
		exit(1);

	rs->db = db_new();


	LOG(SPOCP_INFO) {
		traceLog(LOG_INFO, "Local context: \"%s\"", localcontext);
		traceLog(LOG_INFO, "initializing backends");
		if (srv.root->db)
			plugin_display(srv.plugin);
	}

	if (srv.plugin) {
		run_plugin_init(&srv);
	}

	if ( get_rules( &srv ) != SPOCP_SUCCESS ) 
		exit(1);

	/*ruleset_tree( srv.root, 0);*/

	/* If only testing configuration and rulefile this is as far as I go */
	if (conftest) {
		traceLog(LOG_INFO,"Configuration was OK");
		exit(0);
	}

	gettimeofday(&start, NULL);

	if (srv.port || srv.uds) {

		/*
		 * stdin and stdout will not be used from here on, close to
		 * save file descriptors 
		 */

		fclose(stdin);
		fclose(stdout);

#ifdef HAVE_SSL
		/*
		 * ---------------------------------------------------------- 
		 */
		/*
		 * build our SSL context, whether it will ever be used or not 
		 */

		/*
		 * mutex'es for openSSL to use 
		 */
		THREAD_setup();

		if (srv.certificateFile && srv.privateKey && srv.caList) {
			traceLog(LOG_INFO,"Initializing the TLS/SSL environment");
			if (!(srv.ctx = tls_init(&srv))) {
				return FALSE;
			}
		}

		/*
		 * ---------------------------------------------------------- 
		 */
#endif

#ifdef HAVE_SASL
		{
			int             r = sasl_server_init(sasl_cb, "spocp");
			if (r != SASL_OK) {
				traceLog( LOG_ERR,
				    "Unable to initialized SASL library: %s",
				     sasl_errstring(r, NULL, NULL));
				return FALSE;
			}
		}
#endif

		saci_init();
		if( nodaemon == 0 ) { 
#ifdef HAVE_DAEMON
			if (daemon(1, 1) < 0) {
				fprintf(stderr, "couldn't go daemon\n");
				exit(1);
			}
#else
			daemon_init("spocp", 0);
#endif
		}

		if (srv.pidfile) {
			/*
			 * Write the PID file. 
			 */
			pidfp = fopen(srv.pidfile, "w");

			if (pidfp == (FILE *) 0) {
				fprintf(stderr,
					"Couldn't open pidfile \"%s\"\n",
					srv.pidfile);
				exit(1);
			}
			fprintf(pidfp, "%d\n", (int) getpid());
			fclose(pidfp);
		}

		if (srv.port) {
			LOG(SPOCP_INFO) traceLog( LOG_INFO,
				"Asked to listen on port %d", srv.port);

			if ((srv.listen_fd =
			     spocp_stream_socket(srv.port)) < 0)
				exit(1);

			srv.id = (char *) Malloc(16);
			sprintf(srv.id, "spocp-%d", srv.port);

			srv.type = AF_INET;
		} else {
			LOG(SPOCP_INFO)
			    traceLog(LOG_INFO,"Asked to listen on unix domain socket");
			if ((srv.listen_fd =
			     spocp_unix_domain_socket(srv.uds)) < 0)
				exit(1);

			srv.id = (char *) Malloc(7 + strlen(srv.uds));
			/* Flawfinder: ignore */
			sprintf(srv.id, "spocp-%s", srv.uds);

			srv.type = AF_UNIX;
		}

		xsignal(SIGCHLD, sig_chld);
		xsignal(SIGPIPE, sig_pipe);
		xsignal(SIGINT, sig_int);
		xsignal(SIGTERM, sig_term);
		xsignal(SIGUSR1, sig_usr1);

		clilen = sizeof(cliaddr);

		DEBUG(SPOCP_DSRV) traceLog(LOG_DEBUG,"Creating threads");
		/*
		 * returns the pool the threads are picking work from 
		 */
		srv.work = tpool_init(srv.threads, 64, 1);

		spocp_srv_run(&srv);

	} else {
		conn_t         *conn;

		saci_init();
		DEBUG(SPOCP_DSRV) traceLog(LOG_DEBUG,"---->");

		LOG(SPOCP_INFO) traceLog(LOG_INFO,"Reading STDIN");

		/*
		 * If I want to use this I have to do init_server() first
		 * conn = spocp_open_connection( STDIN_FILENO, &srv ) ; 
		 */
		/*
		 * this is much simpler 
		 */
		conn = conn_new();
		conn_setup(conn, &srv, STDIN_FILENO, "localhost", "127.0.0.1");

		LOG(SPOCP_INFO) traceLog(LOG_INFO,"Running server");

		spocp_server((void *) conn);

		gettimeofday(&end, NULL);

		print_elapsed("query time:", start, end);

		conn_free( conn );
	}

	srv_free( &srv );
	if (cnfg != DEF_CNFG)
		Free( cnfg );

	exit(0);
}
Esempio n. 18
0
int
auth_cyrus_sasl_server(auth_instance *ablock, uschar *data)
{
auth_cyrus_sasl_options_block *ob =
  (auth_cyrus_sasl_options_block *)(ablock->options_block);
uschar *output, *out2, *input, *clear, *hname;
uschar *debug = NULL;   /* Stops compiler complaining */
sasl_callback_t cbs[] = {{SASL_CB_LIST_END, NULL, NULL}};
sasl_conn_t *conn;
char * realm_expanded = NULL;
int rc, firsttime = 1, clen, *negotiated_ssf_ptr = NULL, negotiated_ssf;
unsigned int inlen, outlen;

input = data;
inlen = Ustrlen(data);

HDEBUG(D_auth) debug = string_copy(data);

hname = expand_string(ob->server_hostname);
if (hname && ob->server_realm)
  realm_expanded = CS expand_string(ob->server_realm);
if (!hname  ||  !realm_expanded  && ob->server_realm)
  {
  auth_defer_msg = expand_string_message;
  return DEFER;
  }

if (inlen)
  {
  if ((clen = b64decode(input, &clear)) < 0)
    return BAD64;
  input = clear;
  inlen = clen;
  }

if ((rc = sasl_server_init(cbs, "exim")) != SASL_OK)
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL library";
  return DEFER;
  }

rc = sasl_server_new(CS ob->server_service, CS hname, realm_expanded, NULL,
  NULL, NULL, 0, &conn);

HDEBUG(D_auth)
  debug_printf("Initialised Cyrus SASL server connection; service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n",
      ob->server_service, hname, realm_expanded);

if (rc != SASL_OK )
  {
  auth_defer_msg = US"couldn't initialise Cyrus SASL connection";
  sasl_done();
  return DEFER;
  }

if (tls_in.cipher)
  {
  if ((rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, (sasl_ssf_t *) &tls_in.bits)) != SASL_OK)
    {
    HDEBUG(D_auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n",
        tls_in.bits, sasl_errstring(rc, NULL, NULL));
    auth_defer_msg = US"couldn't set Cyrus SASL EXTERNAL SSF";
    sasl_done();
    return DEFER;
    }
  else
    HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_in.bits);
  }
else
  HDEBUG(D_auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n");

/* So sasl_setprop() documents non-shorted IPv6 addresses which is incredibly
annoying; looking at cyrus-imapd-2.3.x source, the IP address is constructed
with their iptostring() function, which just wraps
getnameinfo(..., NI_NUMERICHOST|NI_NUMERICSERV), which is equivalent to the
inet_ntop which we wrap in our host_ntoa() function.

So the docs are too strict and we shouldn't worry about :: contractions. */

/* Set properties for remote and local host-ip;port */
for (int i = 0; i < 2; ++i)
  {
  struct sockaddr_storage ss;
  int (*query)(int, struct sockaddr *, socklen_t *);
  int propnum, port;
  const uschar *label;
  uschar *address, *address_port;
  const char *s_err;
  socklen_t sslen;

  if (i)
    {
    query = &getpeername;
    propnum = SASL_IPREMOTEPORT;
    label = CUS"peer";
    }
  else
    {
    query = &getsockname;
    propnum = SASL_IPLOCALPORT;
    label = CUS"local";
    }

  sslen = sizeof(ss);
  if ((rc = query(fileno(smtp_in), (struct sockaddr *) &ss, &sslen)) < 0)
    {
    HDEBUG(D_auth)
      debug_printf("Failed to get %s address information: %s\n",
          label, strerror(errno));
    break;
    }

  address = host_ntoa(-1, &ss, NULL, &port);
  address_port = string_sprintf("%s;%d", address, port);

  if ((rc = sasl_setprop(conn, propnum, address_port)) != SASL_OK)
    {
    s_err = sasl_errdetail(conn);
    HDEBUG(D_auth)
      debug_printf("Failed to set %s SASL property: [%d] %s\n",
          label, rc, s_err ? s_err : "<unknown reason>");
    break;
    }
  HDEBUG(D_auth) debug_printf("Cyrus SASL set %s hostport to: %s\n",
      label, address_port);
  }

for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; )
  {
  if (firsttime)
    {
    firsttime = 0;
    HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug);
    rc = sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen,
           (const char **)(&output), &outlen);
    }
  else
    {
    /* make sure that we have a null-terminated string */
    out2 = string_copyn(output, outlen);

    if ((rc = auth_get_data(&input, out2, outlen)) != OK)
      {
      /* we couldn't get the data, so free up the library before
       * returning whatever error we get */
      sasl_dispose(&conn);
      sasl_done();
      return rc;
      }
    inlen = Ustrlen(input);

    HDEBUG(D_auth) debug = string_copy(input);
    if (inlen)
      {
      if ((clen = b64decode(input, &clear)) < 0)
       {
       sasl_dispose(&conn);
       sasl_done();
       return BAD64;
       }
      input = clear;
      inlen = clen;
      }

    HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug);
    rc = sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen);
    }

  if (rc == SASL_BADPROT)
    {
    sasl_dispose(&conn);
    sasl_done();
    return UNEXPECTED;
    }
  if (rc == SASL_CONTINUE)
    continue;

  /* Get the username and copy it into $auth1 and $1. The former is now the
  preferred variable; the latter is the original variable. */

  if ((sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2))) != SASL_OK)
    {
    HDEBUG(D_auth)
      debug_printf("Cyrus SASL library will not tell us the username: %s\n",
	  sasl_errstring(rc, NULL, NULL));
    log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
       "Cyrus SASL username fetch problem: %s", ablock->name, ob->server_mech,
       sasl_errstring(rc, NULL, NULL));
    sasl_dispose(&conn);
    sasl_done();
    return FAIL;
    }
  auth_vars[0] = expand_nstring[1] = string_copy(out2);
  expand_nlength[1] = Ustrlen(out2);
  expand_nmax = 1;

  switch (rc)
    {
    case SASL_FAIL: case SASL_BUFOVER: case SASL_BADMAC: case SASL_BADAUTH:
    case SASL_NOAUTHZ: case SASL_ENCRYPT: case SASL_EXPIRED:
    case SASL_DISABLED: case SASL_NOUSER:
      /* these are considered permanent failure codes */
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
      log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
	 "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
	 sasl_errstring(rc, NULL, NULL));
      sasl_dispose(&conn);
      sasl_done();
      return FAIL;

    case SASL_NOMECH:
      /* this is a temporary failure, because the mechanism is not
       * available for this user. If it wasn't available at all, we
       * shouldn't have got here in the first place...
       */
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
      auth_defer_msg =
	  string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech);
      sasl_dispose(&conn);
      sasl_done();
      return DEFER;

    case SASL_OK:
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL %s authentication succeeded for %s\n",
	    ob->server_mech, auth_vars[0]);

      if ((rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf_ptr)))!= SASL_OK)
	{
	HDEBUG(D_auth)
	  debug_printf("Cyrus SASL library will not tell us the SSF: %s\n",
	      sasl_errstring(rc, NULL, NULL));
	log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
	    "Cyrus SASL SSF value not available: %s", ablock->name, ob->server_mech,
	    sasl_errstring(rc, NULL, NULL));
	sasl_dispose(&conn);
	sasl_done();
	return FAIL;
	}
      negotiated_ssf = *negotiated_ssf_ptr;
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL %s negotiated SSF: %d\n", ob->server_mech, negotiated_ssf);
      if (negotiated_ssf > 0)
	{
	HDEBUG(D_auth)
	  debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf);
	log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
	    "Cyrus SASL SSF %d not supported by Exim", ablock->name, ob->server_mech, negotiated_ssf);
	sasl_dispose(&conn);
	sasl_done();
	return FAIL;
	}

      /* close down the connection, freeing up library's memory */
      sasl_dispose(&conn);
      sasl_done();

      /* Expand server_condition as an authorization check */
      return auth_check_serv_cond(ablock);

    default:
      /* Anything else is a temporary failure, and we'll let SASL print out
       * the error string for us
       */
      HDEBUG(D_auth)
	debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
      auth_defer_msg =
	  string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL));
      sasl_dispose(&conn);
      sasl_done();
      return DEFER;
    }
  }
/* NOTREACHED */
return 0;  /* Stop compiler complaints */
}
XSASL_SERVER_IMPL *xsasl_cyrus_server_init(const char *unused_server_type,
					           const char *path_info)
{
    const char *myname = "xsasl_cyrus_server_init";
    XSASL_SERVER_IMPL *xp;
    int     sasl_status;

#if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \
    || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19))
    int     sasl_major;
    int     sasl_minor;
    int     sasl_step;

    /*
     * DLL hell guard.
     */
    sasl_version_info((const char **) 0, (const char **) 0,
		      &sasl_major, &sasl_minor,
		      &sasl_step, (int *) 0);
    if (sasl_major != SASL_VERSION_MAJOR
#if 0
	|| sasl_minor != SASL_VERSION_MINOR
	|| sasl_step != SASL_VERSION_STEP
#endif
	) {
	msg_warn("incorrect SASL library version. "
	      "Postfix was built with include files from version %d.%d.%d, "
		 "but the run-time library version is %d.%d.%d",
		 SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
		 sasl_major, sasl_minor, sasl_step);
	return (0);
    }
#endif

    if (*var_cyrus_conf_path) {
#ifdef SASL_PATH_TYPE_CONFIG			/* Cyrus SASL 2.1.22 */
	if (sasl_set_path(SASL_PATH_TYPE_CONFIG,
			  var_cyrus_conf_path) != SASL_OK)
	    msg_warn("failed to set Cyrus SASL configuration path: \"%s\"",
		     var_cyrus_conf_path);
#else
	msg_warn("%s is not empty, but setting the Cyrus SASL configuration "
		 "path is not supported with SASL library version %d.%d.%d",
		 VAR_CYRUS_CONF_PATH, SASL_VERSION_MAJOR,
		 SASL_VERSION_MINOR, SASL_VERSION_STEP);
#endif
    }

    /*
     * Initialize the library: load SASL plug-in routines, etc.
     */
    if (msg_verbose)
	msg_info("%s: SASL config file is %s.conf", myname, path_info);
    if ((sasl_status = sasl_server_init(callbacks, path_info)) != SASL_OK) {
	msg_warn("SASL per-process initialization failed: %s",
		 xsasl_cyrus_strerror(sasl_status));
	return (0);
    }

    /*
     * Return a generic XSASL_SERVER_IMPL object. We don't need to extend it
     * with our own methods or data.
     */
    xp = (XSASL_SERVER_IMPL *) mymalloc(sizeof(*xp));
    xp->create = xsasl_cyrus_server_create;
    xp->done = xsasl_cyrus_server_done;
    return (xp);
}