server.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* SASL server API implementation
* Rob Siemborski
* Tim Martin
* $Id: server.c,v 1.123 2003/04/16 19:36:01 rjs3 Exp $
*/
/*
* Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any other legal
* details, please contact
* Office of Technology Transfer
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, PA 15213-3890
* (412) 268-4387, fax: (412) 268-7395
* tech-transfer@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#ifndef macintosh
#endif
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include "sasl.h"
#include "saslint.h"
#include "saslplug.h"
#include "saslutil.h"
#ifndef _SUN_SDK_
#ifdef sun
/* gotta define gethostname ourselves on suns */
extern int gethostname(char *, int);
#endif
#endif /* !_SUN_SDK_ */
#define DEFAULT_CHECKPASS_MECH "auxprop"
/* Contains functions:
*
* sasl_server_init
* sasl_server_new
* sasl_listmech
* sasl_server_start
* sasl_server_step
* sasl_checkpass
* sasl_checkapop
* sasl_user_exists
* sasl_setpass
*/
#ifdef _SUN_SDK_
{
return gctx->sasl_server_active;
}
/*
* server_plug_mutex ensures only one server plugin is init'ed at a time
* If a plugin is loaded more than once, the glob_context may be overwritten
* which may lead to a memory leak. We keep glob_context with each mech
* to avoid this problem.
*/
#else
/* if we've initialized the server sucessfully */
static int _sasl_server_active = 0;
/* For access by other modules */
int _is_sasl_server_active(void) { return _sasl_server_active; }
#endif /* _SUN_SDK_ */
#ifndef _SUN_SDK_
#endif /* !_SUN_SDK_ */
/* set the password for a user
* conn -- SASL connection
* user -- user name
* pass -- plaintext password, may be NULL to remove user
* passlen -- length of password, 0 = strlen(pass)
* oldpass -- NULL will sometimes work
* oldpasslen -- length of password, 0 = strlen(oldpass)
* flags -- see flags below
*
* returns:
* SASL_NOCHANGE -- proper entry already exists
* SASL_NOMECH -- no authdb supports password setting as configured
* SASL_NOVERIFY -- user exists, but no settable password present
* SASL_DISABLED -- account disabled
* SASL_PWLOCK -- password locked
* SASL_WEAKPASS -- password too weak for security policy
* SASL_NOUSERPASS -- user-supplied passwords not permitted
* SASL_FAIL -- OS error
* SASL_BADPARAM -- password too long
* SASL_OK -- successful
*/
const char *user,
const char *oldpass,
unsigned oldpasslen,
unsigned flags)
{
mechanism_t *m;
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
/* check params */
if (!conn) return SASL_BADPARAM;
/* call userdb callback function */
&setpass_cb, &context);
"setpass callback failed for %s: %z",
} else {
"setpass callback succeeded for %s", user);
}
} else {
}
/* now we let the mechanisms set their secrets */
/* can't set pass for this mech */
continue;
}
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
user,
pass,
flags);
mechanism didn't have any user secrets
we now think it does */
} else if (tmpresult == SASL_NOCHANGE) {
} else {
"%s: failed to set secret for %s: %z (%m)",
#ifndef WIN32
#else
#endif
);
}
}
}
#ifdef _SUN_SDK_
static void
{
}
}
#endif /* _SUN_SDK_ */
/* local mechanism which disposes of server */
{
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
}
#ifdef _SUN_SDK_
#else
}
#endif /* _SUN_SDK_ */
if (s_conn->user_realm)
}
#ifdef _SUN_SDK_
{
#else
static int init_mechlist(void)
{
#endif /* _SUN_SDK_ */
/* set util functions - need to do rest */
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
return SASL_NOMEM;
mechlist->mech_length=0;
return SASL_OK;
}
#ifdef _SUN_SDK_
{
void *context;
const char *cp;
/* No sasl_conn_t was given to getcallback, so we provide the
* global callbacks structure */
return (1);
while (*mlist) {
break;
}
return (*mlist != '\0');
}
#endif /* _SUN_SDK_ */
/*
* parameters:
* p - entry point
*/
int sasl_server_add_plugin(const char *plugname,
#ifdef _SUN_SDK_
{
}
int _sasl_server_add_plugin(void *ctx,
const char *plugname,
{
int nplug = 0;
int i;
mechanism_t *m;
/* EXPORT DELETE START */
/* CRYPT DELETE START */
#ifdef _INTEGRATED_SOLARIS_
int sun_reg;
#endif /* _INTEGRATED_SOLARIS_ */
/* CRYPT DELETE END */
/* EXPORT DELETE END */
#else
{
#endif /* _SUN_SDK_ */
int plugcount;
int result;
int version;
int lupe;
if(!plugname || !p) return SASL_BADPARAM;
#ifdef _SUN_SDK_
/* Check to see if this plugin has already been registered */
for (i = 0; i < mechlist->mech_length; i++) {
return SASL_OK;
m = m->next;
}
return result;
#endif /* _SUN_SDK_ */
entry_point = (sasl_server_plug_init_t *)p;
/* call into the shared library asking for information about it */
/* version is filled in with the version of the plugin */
/* EXPORT DELETE START */
/* CRYPT DELETE START */
#ifdef _INTEGRATED_SOLARIS_
#endif /* _INTEGRATED_SOLARIS_ */
/* CRYPT DELETE END */
/* EXPORT DELETE END */
#ifdef _SUN_SDK_
"server add_plugin entry_point error %z", result);
#else
"server add_plugin entry_point error %z\n", result);
#endif /* _SUN_SDK_ */
return result;
}
/* Make sure plugin is using the same SASL version as us */
if (version != SASL_SERVER_PLUG_VERSION)
{
#ifdef _SUN_SDK_
SASL_LOG_ERR, "version mismatch on plugin");
#else
"version mismatch on plugin");
#endif /* _SUN_SDK_ */
return SASL_BADVERS;
}
#ifdef _SUN_SDK_
/* Check plugins to make sure mech_name is non-NULL */
break;
}
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
return SASL_BADPROT;
}
#endif /* _SUN_SDK_ */
{
#ifdef _SUN_SDK_
pluglist++;
continue;
}
nplug++;
#endif /* _SUN_SDK_ */
#ifdef _SUN_SDK_
if (! mech) {
return SASL_NOMEM;
}
#else
if (! mech) return SASL_NOMEM;
#endif /* _SUN_SDK_ */
#ifdef _SUN_SDK_
#endif /* _SUN_SDK_ */
return SASL_NOMEM;
}
#ifdef _SUN_SDK_
/* EXPORT DELETE START */
/* CRYPT DELETE START */
#ifdef _INTEGRATED_SOLARIS_
#endif /* _INTEGRATED_SOLARIS_ */
/* CRYPT DELETE END */
/* EXPORT DELETE END */
/* whether this mech actually has any users in it's db */
#else
/* whether this mech actually has any users in it's db */
#endif /* _SUN_SDK_ */
mechlist->mech_length++;
}
#ifdef _SUN_SDK_
#else
return SASL_OK;
#endif /* _SUN_SDK_ */
}
#ifdef _SUN_SDK_
_sasl_path_info_t *path_info, *p;
#else
static int server_done(void) {
#endif /* _SUN_SDK_ */
mechanism_t *m;
#ifdef _SUN_SDK_
if(!gctx->sasl_server_active)
return SASL_NOTINIT;
if (LOCK_MUTEX(&server_active_mutex) < 0) {
return (SASL_FAIL);
}
if(gctx->sasl_server_active) {
/* Don't de-init yet! Our refcount is nonzero. */
return SASL_CONTINUE;
}
#else
if(!_sasl_server_active)
return SASL_NOTINIT;
else
if(_sasl_server_active) {
/* Don't de-init yet! Our refcount is nonzero. */
return SASL_CONTINUE;
}
#endif /* _SUN_SDK_ */
{
while (m!=NULL)
{
prevm=m;
m=m->next;
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
}
}
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
}
/* Free the auxprop plugins */
#ifdef _SUN_SDK_
p = gctx->splug_path_info;
}
#else
#endif /* _SUN_SDK_ */
return SASL_OK;
}
{
mechanism_t *m;
#ifdef _SUN_SDK_
gctx = _sasl_gbl_ctx();
else
#endif /* _SUN_SDK_ */
if (! mechlist)
return 0;
m!=NULL;
m = m->next)
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
conn,
return 1;
return 0;
}
#ifdef _SUN_SDK_
const sasl_callback_t *verifyfile_cb)
{
int result;
const char *conf_to_config = NULL;
int conf_len;
char *alloc_file_name=NULL;
int len;
int full_file = 0;
int file_exists = 0;
/* get the path to the plugins; for now the config file will reside there */
else {
goto process_file;
}
if (!full_file) {
goto done;
}
/* construct the filename for the config file */
if (! alloc_file_name) {
result = SASL_NOMEM;
goto done;
}
}
/* Check to see if anything has changed */
/* File has not changed */
goto done;
/* No new file, nothing has changed */
if (!file_exists)
goto done;
} else {
if (!file_exists) {
goto done;
}
}
/* Ask the application if it's safe to use this file */
/* returns continue if this file is to be skipped */
/* returns SASL_CONTINUE if doesn't exist
* if doesn't exist we can continue using default behavior
*/
done:
return result;
}
#else
{
int result;
const char *path_to_config=NULL;
const char *c;
unsigned path_len;
char *config_filename=NULL;
int len;
/* get the path to the plugins; for now the config file will reside there */
/* getpath_cb->proc MUST be a sasl_getpath_t; if only c had a type
system */
/* length = length of path + '/' + length of appname + ".conf" + 1
for '\0' */
if(c != NULL)
path_len = c - path_to_config;
else
goto done;
}
/* construct the filename for the config file */
if (! config_filename) {
result = SASL_NOMEM;
goto done;
}
/* Ask the application if it's safe to use this file */
/* returns continue if this file is to be skipped */
/* returns SASL_CONTINUE if doesn't exist
* if doesn't exist we can continue using default behavior
*/
done:
return result;
}
#endif /* _SUN_SDK_ */
/*
* Verify that all the callbacks are valid
*/
{
callbacks++;
}
return SASL_OK;
}
#ifndef _SUN_SDK_
{
int d = 0;
char *field;
/* find end of field */
field[d] = '\0';
return field;
}
struct secflag_map_s {
char *name;
int value;
};
struct secflag_map_s secflag_map[] = {
{ "noplaintext", SASL_SEC_NOPLAINTEXT },
{ "noactive", SASL_SEC_NOACTIVE },
{ "nodictionary", SASL_SEC_NODICTIONARY },
{ "forward_secrecy", SASL_SEC_FORWARD_SECRECY },
{ "noanonymous", SASL_SEC_NOANONYMOUS },
{ "pass_credentials", SASL_SEC_PASS_CREDENTIALS },
{ "mutual_auth", SASL_SEC_MUTUAL_AUTH },
{ NULL, 0x0 }
};
static int parse_mechlist_file(const char *mechlistfile)
{
FILE *f;
char buf[1024];
char *t, *ptr;
int r = 0;
if (!f) return SASL_FAIL;
r = SASL_OK;
if (n == NULL) { r = SASL_NOMEM; break; }
n->condition = SASL_CONTINUE;
/* each line is:
plugin-file WS mech_name WS max_ssf *(WS security_flag) RET
*/
/* grab file */
/* grab mech_name */
/* grab max_ssf */
/* grab security flags */
while (*ptr != '\n') {
struct secflag_map_s *map;
/* read security flag */
map = secflag_map;
break;
}
map++;
}
"%s: couldn't identify flag '%s'",
}
free(t);
}
/* insert mechanism into mechlist */
mechlist->mech_length++;
}
fclose(f);
return r;
}
#endif /* !_SUN_SDK_ */
#ifdef _SUN_SDK_
{
int ret;
const add_plugin_list_t _ep_list[] = {
};
return (ret);
}
#endif /* _SUN_SDK_ */
/* initialize server drivers, done once per process
#ifdef _SUN_SDK_
* callbacks -- callbacks for all server connections
* appname -- name of calling application (for config)
#else
* callbacks -- callbacks for all server connections; must include
* getopt callback
* appname -- name of calling application (for lower level logging)
* results:
* state -- server state
#endif
* returns:
* SASL_OK -- success
* SASL_BADPARAM -- error in config file
* SASL_NOMEM -- memory failure
#ifndef _SUN_SDK_
* SASL_BADVERS -- Mechanism version mismatch
#endif
*/
const char *appname)
#ifdef _SUN_SDK_
{
}
const char *appname)
#endif /* _SUN_SDK_ */
{
int ret;
const sasl_callback_t *vf;
#ifdef _SUN_SDK_
#else
const char *pluginfile = NULL;
#ifdef PIC
void *context;
#endif
const add_plugin_list_t ep_list[] = {
};
#endif /* _SUN_SDK_ */
/* we require the appname to be non-null and short enough to be a path */
return SASL_BADPARAM;
#ifdef _SUN_SDK_
/* Process only one _sasl_server_init() at a time */
if (LOCK_MUTEX(&init_server_mutex) < 0)
return (SASL_FAIL);
if (LOCK_MUTEX(&server_active_mutex) < 0)
return (SASL_FAIL);
if (gctx->sasl_server_active) {
/* We're already active, just increase our refcount */
/* xxx do something with the callback structure? */
return SASL_OK;
}
return ret;
}
#else
if (_sasl_server_active) {
/* We're already active, just increase our refcount */
/* xxx do something with the callback structure? */
return SASL_OK;
}
return ret;
#endif /* _SUN_SDK_ */
/* verify that the callbacks look ok */
#ifdef _SUN_SDK_
return ret;
}
/* If we fail now, we have to call server_done */
/* allocate mechlist and set it to empty */
return SASL_NOMEM;
}
return ret;
}
#else
return ret;
/* If we fail now, we have to call server_done */
_sasl_server_active = 1;
/* allocate mechlist and set it to empty */
server_done();
return SASL_NOMEM;
}
ret = init_mechlist();
server_done();
return ret;
}
#endif /* _SUN_SDK_ */
/* load config file if applicable */
#ifdef _SUN_SDK_
#else
server_done();
#endif /* _SUN_SDK_ */
return ret;
}
/* load internal plugins */
#ifdef _SUN_SDK_
/* NOTE: plugin_list option not supported in SUN SDK */
{
#else
#ifdef PIC
/* delayed loading of plugins? (DSO only, as it doesn't
* make much [any] sense to delay in the static library case) */
== SASL_OK) {
/* No sasl_conn_t was given to getcallback, so we provide the
* global callbacks structure */
}
#endif
if (pluginfile != NULL) {
/* this file should contain a list of plugins available.
we'll load on demand. */
/* Ask the application if it's safe to use this file */
}
}
} else {
#endif /* _SUN_SDK_ */
/* load all plugins now */
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
}
#ifdef _SUN_SDK_
} else {
}
#else
ret = _sasl_build_mechlist();
} else {
server_done();
}
#endif /* _SUN_SDK_ */
return ret;
}
/*
* Once we have the users plaintext password we
* may want to transition them. That is put entries
* for them in the passwd database for other
* stronger mechanism
*
* for example PLAIN -> CRAM-MD5
*/
static int
const char * pass,
unsigned passlen)
{
const char *dotrans = "n";
void *context;
if (! conn)
return SASL_BADPARAM;
/* check if this is enabled: default to false */
{
}
/* ok, it's on! */
pass,
NULL, 0, 0);
}
}
/* create context for a single SASL connection
* service -- registered name of the service using SASL (e.g. "imap")
* serverFQDN -- Fully qualified domain name of server. NULL means use
* gethostname() or equivalent.
* Useful for multi-homed servers.
* user_realm -- permits multiple user realms on server, NULL = default
* (if NULL, then mechanisms requiring IPaddr are disabled)
* (if NULL, then mechanisms requiring IPaddr are disabled)
* callbacks -- callbacks (e.g., authorization, lang, new getopt context)
* flags -- usage flags (see above)
* returns:
* pconn -- new connection context
*
* returns:
* SASL_OK -- success
* SASL_NOMEM -- not enough memory
*/
int sasl_server_new(const char *service,
const char *serverFQDN,
const char *user_realm,
const char *iplocalport,
const char *ipremoteport,
const sasl_callback_t *callbacks,
unsigned flags,
sasl_conn_t **pconn)
#ifdef _SUN_SDK_
{
}
int _sasl_server_new(void *ctx,
const char *service,
const char *serverFQDN,
const char *user_realm,
const char *iplocalport,
const char *ipremoteport,
const sasl_callback_t *callbacks,
unsigned flags,
sasl_conn_t **pconn)
#endif /* _SUN_SDK_ */
{
int result;
void *context;
const char *log_level;
#ifdef _SUN_SDK_
#else
if (_sasl_server_active==0) return SASL_NOTINIT;
#endif /* _SUN_SDK_ */
#ifdef _SUN_SDK_
#endif /* _SUN_SDK_ */
/* make sparams */
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
goto done_error;
/* set util functions - need to do rest */
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
if (!utils) {
result = SASL_NOMEM;
goto done_error;
}
#ifdef _SUN_SDK_
#else /* _SUN_SDK_ */
#endif /* _SUN_SDK_ */
/* Setup the propctx -> We'll assume the default size */
result = SASL_NOMEM;
goto done_error;
}
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
if (user_realm) {
} else {
/* the sparams is already zeroed */
}
#ifdef _SUN_SDK_
#endif /* _SUN_SDK_ */
}
return result;
}
/*
* The rule is:
* IF mech strength + external strength < min ssf THEN FAIL
* We also have to look at the security properties and make sure
* that this mechanism has everything we want
*/
{
const sasl_server_plug_t *plug;
int myflags;
void *context;
sasl_ssf_t minssf = 0;
#ifdef _SUN_SDK_
#endif /* _SUN_SDK_ */
if(!conn) return 0;
#ifdef _SUN_SDK_
#endif /* _SUN_SDK_ */
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
return 0;
}
/* get the list of allowed mechanisms (default = all) */
== SASL_OK) {
/* if we have a list, check the plugin against it */
if (mlist) {
const char *cp;
while (*mlist) {
break;
}
}
if (!*mlist) return 0; /* reached EOS -> not in our list */
}
}
/* setup parameters for the call to mech_avail */
/* Check if we have banished this one already */
/* If it's not mech_avail'd, then stop now */
break;
}
}
/* EXPORT DELETE START */
/* CRYPT DELETE START */
#ifdef _INTEGRATED_SOLARIS_
}
#endif /* _INTEGRATED_SOLARIS_ */
/* CRYPT DELETE END */
/* EXPORT DELETE END */
minssf = 0;
} else {
}
/* Generic mechanism */
/* EXPORT DELETE START */
/* CRYPT DELETE START */
#ifdef _INTEGRATED_SOLARIS_
/* If not SUN supplied mech, it has no strength */
#else
/* CRYPT DELETE END */
/* EXPORT DELETE END */
/* EXPORT DELETE START */
/* CRYPT DELETE START */
#endif /* _INTEGRATED_SOLARIS_ */
/* CRYPT DELETE END */
/* EXPORT DELETE END */
#ifdef _INTEGRATED_SOLARIS_
#else
#endif /* _INTEGRATED_SOLARIS_ */
return 0; /* too weak */
}
if(plug->mech_avail
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
/* Mark this mech as no good for this connection */
if(!cur) {
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
return 0;
}
/* Error should be set by mech_avail call */
return 0;
} else if(context) {
/* Save this context */
if(!cur) {
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
return 0;
}
}
/* Generic mechanism */
/* EXPORT DELETE START */
/* CRYPT DELETE START */
#ifdef _INTEGRATED_SOLARIS_
/* If not SUN supplied mech, it has no strength */
#else
/* CRYPT DELETE END */
/* EXPORT DELETE END */
/* EXPORT DELETE START */
/* CRYPT DELETE START */
#endif /* _INTEGRATED_SOLARIS_ */
/* CRYPT DELETE END */
/* EXPORT DELETE END */
#ifdef _INTEGRATED_SOLARIS_
#else
#endif /* _INTEGRATED_SOLARIS_ */
return 0; /* too weak */
}
#ifndef _SUN_SDK_
/* if there are no users in the secrets database we can't use this
mechanism */
return 0;
}
#endif /* !_SUN_SDK_ */
/* Can it meet our features? */
return 0;
}
/* security properties---if there are any flags that differ and are
in what the connection are requesting, then fail */
/* special case plaintext */
/* if there's an external layer this is no longer plaintext */
}
/* do we want to special case SASL_SEC_PASS_CREDENTIALS? nah.. */
#ifdef _INTEGRATED_SOLARIS_
gettext("security flags do not match required"));
#else
"security flags do not match required");
#endif /* _INTEGRATED_SOLARIS_ */
return 0;
}
/* Check Features */
/* We no longer support sasl_server_{get,put}secret */
#ifdef _SUN_SDK_
"mech %s requires unprovided secret facility",
#else
sasl_seterror(conn, 0,
"mech %s requires unprovided secret facility",
#endif /* _SUN_SDK_ */
return 0;
}
return 1;
}
/*
* make the authorization
*
*/
{
int ret;
void *auth_context;
/* now let's see if authname is allowed to proxy for username! */
/* check the proxy callback */
}
}
/* start a mechanism exchange within a connection context
* mech -- the mechanism name client requested
* clientin -- client initial response (NUL terminated), NULL if empty
* clientinlen -- length of initial response
* serverout -- initial server challenge, NULL if done
* (library handles freeing this string)
* serveroutlen -- length of initial server challenge
#ifdef _SUN_SDK_
* conn -- the sasl connection
#else
* output:
* pconn -- the connection negotiation state on success
#endif
*
* Same returns as sasl_server_step() or
* SASL_NOMECH if mechanism not available.
*/
const char *mech,
const char *clientin,
unsigned clientinlen,
const char **serverout,
unsigned *serveroutlen)
{
int result;
mechanism_t *m;
#ifdef _SUN_SDK_
if (! conn)
return SASL_BADPARAM;
(void)_load_server_plugins(gctx);
return (result);
#else
if (_sasl_server_active==0) return SASL_NOTINIT;
/* make sure mech is valid mechanism
if not return appropriate error */
/* check parameters */
if(!conn) return SASL_BADPARAM;
#endif /* _SUN_SDK_ */
if(serveroutlen) *serveroutlen = 0;
while (m!=NULL)
{
{
break;
}
m=m->next;
}
if (m==NULL) {
#ifdef _INTEGRATED_SOLARIS_
#else
#endif /* _INTEGRATED_SOLARIS_ */
goto done;
}
#ifdef _SUN_SDK_
#endif /*_SUN_SDK_ */
/* Make sure that we're willing to use this mech */
if (! mech_permitted(conn, m)) {
goto done;
}
#ifdef _SUN_SDK_
}
#else
if (m->condition == SASL_CONTINUE) {
int l = 0;
/* need to load this plugin */
result = _sasl_get_plugin(m->f,
&library);
(void **)&entry_point);
}
}
/* find the correct mechanism in this plugin */
for (l = 0; l < plugcount; l++) {
}
if (l == plugcount) {
}
}
/* check that the parameters are the same */
"%s: security parameters don't match mechlist file",
}
}
/* copy mechlist over */
}
/* The library will eventually be freed, don't sweat it */
}
}
#endif /* !_SUN_SDK_ */
/* We used to setup sparams HERE, but now it's done
inside of mech_permitted (which is called above) */
#ifdef _SUN_SDK_
"Got past mech_permitted with a disallowed mech!");
#else
sasl_seterror(conn, 0,
"Got past mech_permitted with a disallowed mech!");
#endif /* _SUN_SDK_ */
return SASL_NOMECH;
}
/* If we find it, we need to pull cur out of the
list so it won't be freed later! */
}
}
/* Note that we don't hand over a new challenge */
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
NULL,
0,
} else {
/* the work was already done by mech_avail! */
}
if(clientin) {
/* Remote sent first, but mechanism does not support it.
* RFC 2222 says we fail at this point. */
#ifdef _SUN_SDK_
"Remote sent first but mech does not allow it.");
#else
sasl_seterror(conn, 0,
"Remote sent first but mech does not allow it.");
#endif /* _SUN_SDK_ */
} else {
/* Mech wants client-first, so let them have it */
}
} else {
/* Mech wants client first anyway, so we should do that */
*serverout = "";
*serveroutlen = 0;
} else {
/* Mech wants server-first, so let them have it */
}
}
}
done:
&& result != SASL_CONTINUE
&& result != SASL_INTERACT) {
}
}
}
/* perform one step of the SASL exchange
* inputlen & input -- client data
* NULL on first step if no optional client step
* outputlen & output -- set to the server data to transmit
* to the client in the next step
* (library handles freeing this)
*
* returns:
* SASL_OK -- exchange is complete.
* SASL_CONTINUE -- indicates another step is necessary.
* SASL_TRANS -- entry for user exists, but not for mechanism
* and transition is possible
* SASL_BADPARAM -- service name needed
* SASL_BADPROT -- invalid input from client
* ...
*/
const char *clientin,
unsigned clientinlen,
const char **serverout,
unsigned *serveroutlen)
{
int ret;
#ifdef _SUN_SDK_
/* check parameters */
#else
/* check parameters */
if (_sasl_server_active==0) return SASL_NOTINIT;
#endif /* _SUN_SDK_ */
if (!conn) return SASL_BADPARAM;
/* If we've already done the last send, return! */
return SASL_OK;
}
/* Don't do another step if the plugin told us that we're done */
return SASL_FAIL;
}
if(serveroutlen) *serveroutlen = 0;
}
/* if we're done, we need to watch out for the following:
* 1. the mech does server-send-last
* 2. the protocol does not
*
* in this case, return SASL_CONTINUE and remember we are done.
*/
ret = SASL_CONTINUE;
}
}
#ifdef _SUN_SDK_
"mech did not call canon_user for both authzid "
"and authid");
#else
sasl_seterror(conn, 0,
"mech did not call canon_user for both authzid " \
"and authid");
#endif /* _SUN_SDK_ */
ret = SASL_BADPROT;
}
}
&& ret != SASL_CONTINUE
&& ret != SASL_INTERACT) {
}
}
}
/* returns the length of all the mechanisms
* added up
*/
#ifdef _SUN_SDK_
{
#else
static unsigned mech_names_len()
{
#endif /* _SUN_SDK_ */
unsigned result = 0;
return result;
}
/* This returns a list of mechanisms in a NUL-terminated string
*
* The default behavior is to seperate with spaces if sep==NULL
*/
const char *prefix,
const char *sep,
const char *suffix,
const char **result,
unsigned *plen,
int *pcount)
{
int lup;
int ret;
int resultlen;
int flag;
const char *mysep;
#ifdef _SUN_SDK_
if (!conn) return SASL_BADPARAM;
/* if there hasn't been a sasl_sever_init() fail */
(void)_load_server_plugins(gctx);
#else
/* if there hasn't been a sasl_sever_init() fail */
if (_sasl_server_active==0) return SASL_NOTINIT;
if (!conn) return SASL_BADPARAM;
#endif /* _SUN_SDK_ */
if (! result)
*plen = 0;
*pcount = 0;
if (sep) {
} else {
mysep = " ";
}
#ifdef _SUN_SDK_
#else
+ mech_names_len()
#endif /* _SUN_SDK_ */
+ 1;
if (prefix)
else
flag = 0;
/* make list */
/* currently, we don't use the "user" parameter for anything */
(*pcount)++;
/* print seperator */
if (flag) {
} else {
flag = 1;
}
/* now print the mechanism name */
}
}
if (suffix)
return SASL_OK;
}
#ifdef _SUN_SDK_
#else
#endif /* _SUN_SDK_ */
{
#ifdef _SUN_SDK_
#else
if(!_sasl_server_active) return NULL;
#endif /* _SUN_SDK_ */
/* make list */
else if(!next) {
do {
} while(next);
return NULL;
}
if(!retval) {
} else {
}
}
return retval;
}
static int is_mech(const char *t, const char *m)
{
}
/* returns OK if it's valid */
const char *user,
const char *pass,
{
int result;
void *context;
struct sasl_verify_password_s *v;
/* call userdb callback function, if available */
&checkpass_cb, &context);
return SASL_OK;
}
/* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
== SASL_OK) {
}
for (v = _sasl_verify_password; v->name; v++) {
s_conn->user_realm);
break;
}
}
/* skip to next mech in list */
}
}
if (result == SASL_NOMECH) {
/* no mechanism available ?!? */
}
#ifdef _INTEGRATED_SOLARIS_
#else
#endif /* _INTEGRATED_SOLARIS_ */
}
/* check if a plaintext password is valid
* if user is NULL, check if plaintext passwords are enabled
* inputs:
* user -- user to query in current user_domain
* userlen -- length of username, 0 = strlen(user)
* pass -- plaintext password to check
* passlen -- length of password, 0 = strlen(pass)
* returns
* SASL_OK -- success
* SASL_NOMECH -- mechanism not supported
* SASL_NOVERIFY -- user found, but no verifier
* SASL_NOUSER -- user not found
*/
const char *user,
#ifdef _SUN_SDK_
unsigned userlen,
#else /* _SUN_SDK_ */
#endif /* _SUN_SDK_ */
const char *pass,
unsigned passlen)
{
int result;
#ifdef _SUN_SDK_
/* A NULL user means the caller is checking if plaintext authentication
* is enabled. But if no connection context is supplied, we have no
* appropriate policy to check against. So for consistant global
* behavior we always say plaintext is enabled in this case.
*/
if (!conn) return SASL_BADPARAM;
/* Check connection security policy to see if plaintext password
* authentication is permitted.
*
* XXX TODO FIXME:
* This should call mech_permitted with the PLAIN mechanism,
* since all plaintext mechanisms should fall under the same
* security policy guidelines. But to keep code changes and
* risk to a minimum at this juncture, we do the minimal
* security strength and plaintext policy checks which are
* most likely to be deployed and useful in the field.
*/
if (!user)
return SASL_OK;
#else
if (_sasl_server_active==0) return SASL_NOTINIT;
/* check if it's just a query if we are enabled */
if (!user)
return SASL_OK;
if (!conn) return SASL_BADPARAM;
#endif /* _SUN_SDK_ */
/* check params */
/* canonicalize the username */
/* Check the password */
#ifdef _SUN_SDK_
}
#endif /* _SUN_SDK_ */
}
/* check if a user exists on server
* conn -- connection context (may be NULL, used to hold last error)
* service -- registered name of the service using SASL (e.g. "imap")
* user_realm -- permits multiple user realms on server, NULL = default
* user -- NUL terminated user name
*
* returns:
* SASL_OK -- success
* SASL_DISABLED -- account disabled [FIXME: currently not detected]
* SASL_NOUSER -- user not found
* SASL_NOVERIFY -- user found, but no usable mechanism [FIXME: not supported]
* SASL_NOMECH -- no mechanisms enabled
*/
const char *service,
const char *user_realm,
const char *user)
{
int result=SASL_NOMECH;
void *context;
struct sasl_verify_password_s *v;
#ifdef _SUN_SDK_
/* check params */
#else
/* check params */
if (_sasl_server_active==0) return SASL_NOTINIT;
#endif /* _SUN_SDK_ */
if (!conn) return SASL_BADPARAM;
/* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
== SASL_OK) {
}
for (v = _sasl_verify_password; v->name; v++) {
break;
}
}
/* skip to next mech in list */
}
}
/* Screen out the SASL_BADPARAM response
* we'll get from not giving a password */
if(result == SASL_BADPARAM) {
}
if (result == SASL_NOMECH) {
/* no mechanism available ?!? */
#ifndef _SUN_SDK_
#endif /* !_SUN_SDK_ */
}
}
/* check if an apop exchange is valid
* (note this is an optional part of the SASL API)
* if challenge is NULL, just check if APOP is enabled
* inputs:
* challenge -- challenge which was sent to client
* challen -- length of challenge, 0 = strlen(challenge)
* response -- client response, "<user> <digest>" (RFC 1939)
* resplen -- length of response, 0 = strlen(response)
* returns
* SASL_OK -- success
* SASL_BADAUTH -- authentication failed
* SASL_BADPARAM -- missing challenge
* SASL_BADPROT -- protocol error (e.g., response in wrong format)
* SASL_NOVERIFY -- user found, but no verifier
* SASL_NOMECH -- mechanism not supported
* SASL_NOUSER -- user not found
*/
#ifdef DO_SASL_CHECKAPOP
const char *challenge,
const char *response,
#else
#endif
{
#ifdef DO_SASL_CHECKAPOP
int result;
#ifdef _SUN_SDK_
if (gctx->sasl_server_active==0)
return SASL_NOTINIT;
#else
if (_sasl_server_active==0)
return SASL_NOTINIT;
#endif /* _SUN_SDK_ */
/* check if it's just a query if we are enabled */
if(!challenge)
return SASL_OK;
/* check params */
if (!conn) return SASL_BADPARAM;
if (!response)
/* Parse out username and digest.
*
* Per RFC 1939, response must be "<user> <digest>", where
* <digest> is a 16-octet value which is sent in hexadecimal
* format, using lower-case ASCII characters.
*/
{
#ifdef _INTEGRATED_SOLARIS_
#else
#endif /* _INTEGRATED_SOLARIS_ */
}
{
}
/* Cannonify it */
/* Do APOP verification */
/* If verification failed, we don't want to encourage getprop to work */
}
#else /* sasl_checkapop was disabled at compile time */
"sasl_checkapop called, but was disabled at compile time");
#endif /* DO_SASL_CHECKAPOP */
}