/* * Copyright (c) 2004, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: sasl-common.c,v 1.19 2007/07/28 16:45:03 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/net.h" #include "sm/sasl.h" #include "sm/io.h" #if MTA_USE_SASL static sasl_callback_t srvcallbacks[] = { #if 0 { SASL_CB_VERIFYFILE, &safesaslfile, NULL }, { SASL_CB_PROXY_POLICY, &proxy_policy, NULL }, #endif { SASL_CB_LIST_END, NULL, NULL } }; #if !HAVE_SASL_VERSION_INFO void sasl_version_info(const char **implementation, const char **version_string, int *version_major, int *version_minor, int *version_step, int *version_patch) { int v; sasl_version(implementation, &v); if (version_major != NULL) *version_major = (v >> 24) & 0xff; if (version_minor != NULL) *version_minor = (v >> 16) & 0xff; if (version_step != NULL) *version_step = v & 0xffff; if (version_patch != NULL) *version_patch = 0; } #endif /* ** SM_SASLVERSIONOK -- check Cyrus SASL version ** ** Parameters: ** none ** ** Returns: ** usual sm_error code. */ sm_ret_T sm_saslversionok(void) { int version_major, version_minor, version_step; sasl_version_info(NULL, NULL, &version_major, &version_minor, &version_step, NULL); if (SASL_VERSION_MAJOR == version_major && SASL_VERSION_MINOR == version_minor && SASL_VERSION_STEP == version_step) return SM_SUCCESS; else return sm_error_perm(SM_EM_SASL, SM_E_VER_MIX); } /* ** SM_SASLVERSIONPRT -- show Cyrus SASL version ** ** Parameters: ** fp -- file for output ** ** Returns: ** usual sm_error code. */ sm_ret_T sm_saslversionprt(sm_file_T *fp) { const char *implementation, *version_string; int version_major, version_minor, version_step, version_patch; sasl_version_info(&implementation, &version_string, &version_major, &version_minor, &version_step, &version_patch); sm_io_fprintf(fp, "%s versions:\n" "compiled against: version=%d.%d.%d\n" "linked against: version=%d.%d.%d\n" #if 0 "implementation=%s, version=%s, patch=%d\n" #endif , implementation , SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP , version_major, version_minor, version_step #if 0 , implementation, version_string, version_patch #endif ); return sm_saslversionok(); } /* ** SM_SASL_INIT -- initialize SASL ** ** Parameters: ** server -- server side? ** flags -- (security) flags ** srvcbs -- server call backs ** lctx -- log context ** psasl_ctx -- (pointer to) SASL context (output) ** ** Returns: ** usual return code */ sm_ret_T sm_sasl_init(bool server, uint32_t flags, sasl_callback_t *srvcbs, sm_log_ctx_P lctx, sm_sasl_ctx_P *psasl_ctx) { sm_ret_T ret; sm_sasl_ctx_P sasl_ctx; SM_REQUIRE(psasl_ctx != NULL); ret = SM_SUCCESS; *psasl_ctx = NULL; sasl_ctx = sm_zalloc(sizeof(*sasl_ctx)); if (sasl_ctx == NULL) return sm_err_temp(ENOMEM); sasl_ctx->sm_sasl_sec_flags = flags; sasl_ctx->sm_sasl_lctx = lctx; #if 0 sasl_set_alloc(sm_sasl_malloc, sm_sasl_calloc, sm_sasl_realloc, sm_sasl_free); #endif if (server) ret = sasl_server_init((srvcbs != NULL) ? srvcbs : srvcallbacks , "meta1"); *psasl_ctx = sasl_ctx; return ret; } /* ** ITEMINLIST -- does item appear in list? ** ** Check whether item appears in list (which must be separated by a ** character in delim) as a "word", i.e. it must appear at the begin ** of the list or after a space, and it must end with a space or the ** end of the list. ** ** Parameters: ** item -- item to search. ** list -- list of items. ** delim -- list of delimiters. ** ** Returns: ** pointer to occurrence (NULL if not found). */ char * iteminlist(const char *item, char *list, const char *delim) { char *s; int len; if (list == NULL || *list == '\0') return NULL; if (item == NULL || *item == '\0') return NULL; s = list; len = strlen(item); while (s != NULL && *s != '\0') { if (strncasecmp(s, item, len) == 0 && (s[len] == '\0' || strchr(delim, s[len]) != NULL)) return s; s = strpbrk(s, delim); if (s != NULL) while (*++s == ' ') continue; } return NULL; } /* ** SM_SASLMECHS -- get list of possible AUTH mechanisms ** ** Parameters: ** sasl_ctx -- meta1 SASL context ** conn -- SASL connection (context) ** mech_list -- list of allowed SASL mechanisms (output) ** ** Returns: ** number of mechs. */ sm_ret_T sm_saslmechs(sm_sasl_ctx_P sasl_ctx, sasl_conn_t *conn, char **mech_list) { int len, num, result; SM_REQUIRE(sasl_ctx != NULL); SM_REQUIRE(mech_list != NULL); SM_REQUIRE(conn != NULL); /* "user" is currently unused */ result = sasl_listmech(conn, NULL, "", " ", "", (const char **)mech_list, (uint *)&len, &num); if (result != SASL_OK) num = 0; if (num == 0) { *mech_list = NULL; /* be paranoid... */ if (!SM_IS_FLAG(sasl_ctx->sm_sasl_flags, SASL_FL_NOMECH)) { sm_log_write(sasl_ctx->sm_sasl_lctx, NULL, NULL, /* todo: create logging cat! */ SM_LOG_WARN, 9, "sev=WARN, func=sm_saslmechs, status=no_mechanisms"); SM_SET_FLAG(sasl_ctx->sm_sasl_flags, SASL_FL_NOMECH); } } return num; } #endif /* MTA_USE_SASL */