bool setsecprops() { sasl_security_properties_t secprops; secprops.min_ssf = ssf_min; secprops.max_ssf = ssf_max; secprops.maxbufsize = SASL_BUFSIZE; secprops.property_names = NULL; secprops.property_values = NULL; secprops.security_flags = secflags; int r = sasl_setprop(con, SASL_SEC_PROPS, &secprops); if(r != SASL_OK) return false; if(!ext_authid.isEmpty()) { QByteArray cs = ext_authid.toLatin1(); const char *authid = cs.data(); sasl_ssf_t ssf = ext_ssf; r = sasl_setprop(con, SASL_SSF_EXTERNAL, &ssf); if(r != SASL_OK) return false; r = sasl_setprop(con, SASL_AUTH_EXTERNAL, &authid); if(r != SASL_OK) return false; } return true; }
static int __pmAuthServerSetProperties(sasl_conn_t *conn, int ssf) { int saslsts; sasl_security_properties_t props; /* set external security strength factor */ saslsts = sasl_setprop(conn, SASL_SSF_EXTERNAL, &ssf); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { pmNotifyErr(LOG_ERR, "SASL setting external SSF to %d: %s", ssf, sasl_errstring(saslsts, NULL, NULL)); return __pmSecureSocketsError(saslsts); } /* set general security properties */ memset(&props, 0, sizeof(props)); props.maxbufsize = LIMIT_AUTH_PDU; props.max_ssf = UINT_MAX; saslsts = sasl_setprop(conn, SASL_SEC_PROPS, &props); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { pmNotifyErr(LOG_ERR, "SASL setting security properties: %s", sasl_errstring(saslsts, NULL, NULL)); return __pmSecureSocketsError(saslsts); } return 0; }
int ArgusInitializeAuthentication (struct ARGUS_INPUT *input) { int retn = 1; #ifdef ARGUS_SASL struct sockaddr_in localaddr, remoteaddr; int salen, fd = input->fd; char *localhostname = NULL; if ((retn = sasl_client_init(RaCallBacks)) != SASL_OK) ArgusLog (LOG_ERR, "ArgusInitializeAuthentication() sasl_client_init %d", retn); localhostname = ArgusCalloc (1, 1024); gethostname(localhostname, 1024); if (!strchr (localhostname, '.')) { strcat (localhostname, "."); getdomainname (&localhostname[strlen(localhostname)], 1024 - strlen(localhostname)); } if ((retn = sasl_client_new("argus", localhostname, NULL, SASL_SECURITY_LAYER, &input->sasl_conn)) != SASL_OK) ArgusLog (LOG_ERR, "ArgusInitializeAuthentication() sasl_client_new %d", retn); /* set external properties here sasl_setprop(input->sasl_conn, SASL_SSF_EXTERNAL, &extprops); */ /* set required security properties here sasl_setprop(input->sasl_conn, SASL_SEC_PROPS, &secprops); */ /* set ip addresses */ salen = sizeof(localaddr); if (getsockname(fd, (struct sockaddr *)&localaddr, &salen) < 0) perror("getsockname"); salen = sizeof(remoteaddr); if (getpeername(fd, (struct sockaddr *)&remoteaddr, &salen) < 0) perror("getpeername"); if ((retn = sasl_setprop(input->sasl_conn, SASL_IP_LOCAL, &localaddr)) != SASL_OK) ArgusLog (LOG_ERR, "ArgusInitializeAuthentication() error setting localaddr %d", retn); if ((retn = sasl_setprop(input->sasl_conn, SASL_IP_REMOTE, &remoteaddr)) != SASL_OK) ArgusLog (LOG_ERR, "ArgusInitializeAuthentication() error setting remoteaddr %d", retn); retn = 1; #endif #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusInitializeAuthentication () returning %d\n", retn); #endif return (retn); }
EXPORTED int backend_starttls( struct backend *s, struct tls_cmd_t *tls_cmd, const char *c_cert_file, const char *c_key_file) { #ifndef HAVE_SSL return -1; #else char *auth_id = NULL; int *layerp = NULL; int r = 0; if (tls_cmd) { char buf[2048]; /* send starttls command */ prot_printf(s->out, "%s\r\n", tls_cmd->cmd); prot_flush(s->out); /* check response */ if (!prot_fgets(buf, sizeof(buf), s->in) || strncmp(buf, tls_cmd->ok, strlen(tls_cmd->ok))) return -1; } r = tls_init_clientengine(5, c_cert_file, c_key_file); if (r == -1) return -1; /* SASL and openssl have different ideas about whether ssf is signed */ layerp = (int *) &s->ext_ssf; r = tls_start_clienttls(s->in->fd, s->out->fd, layerp, &auth_id, &s->tlsconn, &s->tlssess); if (r == -1) return -1; if (s->saslconn) { r = sasl_setprop(s->saslconn, SASL_SSF_EXTERNAL, &s->ext_ssf); if (r == SASL_OK) r = sasl_setprop(s->saslconn, SASL_AUTH_EXTERNAL, auth_id); if (auth_id) free(auth_id); if (r != SASL_OK) return -1; } prot_settls(s->in, s->tlsconn); prot_settls(s->out, s->tlsconn); ask_capability(s, /*dobanner*/1, tls_cmd->auto_capa); return 0; #endif /* HAVE_SSL */ }
/* cyrussasl.setprop(conn, propnum, val) * * conn: the conn pointer from cyrussasl.server_new(). * propnum: an integer corresponding to the property to set * val: a lua string object * * Throws Lua errors if it fails (as it should not typically fail). * Does not return any value. */ static int cyrussasl_sasl_setprop(lua_State *l) { int err; int proptype; const void *proparg; struct _sasl_ctx *ctx = NULL; int numargs = lua_gettop(l); if (numargs != 3) { lua_pushstring(l, "usage: cyrussasl.setprop(conn, propnum, propval)"); lua_error(l); return 0; } ctx = get_context(l, 1); proptype = tointeger(l, 2); proparg = tolstring(l, 3, NULL); err = sasl_setprop(ctx->conn, proptype, &proparg); if ( err != SASL_OK ) { const char *ret = get_context_message(ctx); if (ret) lua_pushstring(l, ret); else lua_pushstring(l, "sasl_setprop failed"); lua_error(l); return 0; } return 0; }
/* cyrussasl.setssf(conn, min_ssf, max_ssf) * * conn: the conn pointer from cyrussasl.server_new(). * min_ssf, max_ssf: set the minimum and maximum security strength factor * required for this AuthN. * * Throws Lua errors if it fails (as it should not typically fail). * Does not return any value. */ static int cyrussasl_setssf(lua_State *l) { sasl_security_properties_t secprops; int err; int min_ssf, max_ssf; struct _sasl_ctx *ctx = NULL; int numargs = lua_gettop(l); if (numargs != 3) { lua_pushstring(l, "usage: cyrussasl.setssf(conn, min_ssf, max_ssf)"); lua_error(l); return 0; } ctx = get_context(l, 1); min_ssf = tointeger(l, 2); max_ssf = tointeger(l, 3); memset(&secprops, 0L, sizeof(secprops)); secprops.min_ssf = min_ssf; secprops.max_ssf = max_ssf; err = sasl_setprop(ctx->conn, SASL_SEC_PROPS, &secprops); if ( err != SASL_OK ) { lua_pushstring(l, "setssf failed"); lua_error(l); return 0; } return 0; }
int virNetSASLSessionSecProps(virNetSASLSessionPtr sasl, int minSSF, int maxSSF, bool allowAnonymous) { sasl_security_properties_t secprops; int err; int ret = -1; VIR_DEBUG("minSSF=%d maxSSF=%d allowAnonymous=%d maxbufsize=%zu", minSSF, maxSSF, allowAnonymous, sasl->maxbufsize); virObjectLock(sasl); memset(&secprops, 0, sizeof(secprops)); secprops.min_ssf = minSSF; secprops.max_ssf = maxSSF; secprops.maxbufsize = sasl->maxbufsize; secprops.security_flags = allowAnonymous ? 0 : SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops); if (err != SASL_OK) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot set security props %d (%s)"), err, sasl_errstring(err, NULL, NULL)); goto cleanup; } ret = 0; cleanup: virObjectUnlock(sasl); return ret; }
bool pni_init_client(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_client_init(NULL); if (result!=SASL_OK) break; const sasl_callback_t *callbacks = sasl->username ? sasl->password ? pni_user_password_callbacks : pni_user_callbacks : NULL; result = sasl_client_new(amqp_service, sasl->remote_fqdn, NULL, NULL, callbacks, 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); }
static int do_starttls(struct backend *s) { #ifndef HAVE_SSL return -1; #else const struct tls_cmd_t *tls_cmd = &s->prot->tls_cmd; char buf[2048]; int r; int *layerp; char *auth_id; sasl_ssf_t ssf; /* send starttls command */ prot_printf(s->out, "%s\r\n", tls_cmd->cmd); prot_flush(s->out); /* check response */ if (!prot_fgets(buf, sizeof(buf), s->in) || strncmp(buf, tls_cmd->ok, strlen(tls_cmd->ok))) return -1; r = tls_init_clientengine(5, "", ""); if (r == -1) return -1; /* SASL and openssl have different ideas about whether ssf is signed */ layerp = (int *) &ssf; r = tls_start_clienttls(s->in->fd, s->out->fd, layerp, &auth_id, &s->tlsconn, &s->tlssess); if (r == -1) return -1; r = sasl_setprop(s->saslconn, SASL_SSF_EXTERNAL, &ssf); if (r == SASL_OK) r = sasl_setprop(s->saslconn, SASL_AUTH_EXTERNAL, auth_id); if (auth_id) free(auth_id); if (r != SASL_OK) return -1; prot_settls(s->in, s->tlsconn); prot_settls(s->out, s->tlsconn); ask_capability(s, /*dobanner*/1, s->prot->tls_cmd.auto_capa); return 0; #endif /* HAVE_SSL */ }
/* * per SASL session initialization. * We keep session data in Connection layer. */ DWORD VmDirSASLSessionInit( PVDIR_SASL_BIND_INFO pSaslBindInfo ) { DWORD dwError = 0; sasl_conn_t* pLocalSaslCtx = NULL; // start new sasl context dwError = sasl_server_new( "ldap", // service protocol NULL, // need realm here? NULL, NULL, NULL, NULL, // per session CB 0, // default security flag &pLocalSaslCtx); BAIL_ON_SASL_ERROR(dwError) // default security properties dwError = sasl_setprop( pLocalSaslCtx, SASL_SEC_PROPS, &gSASLSecurityProps ); BAIL_ON_SASL_ERROR(dwError); pSaslBindInfo->pSaslCtx = pLocalSaslCtx; cleanup: return dwError; sasl_error: if (pLocalSaslCtx) { sasl_dispose(&pLocalSaslCtx); } memset(pSaslBindInfo, 0, sizeof(*pSaslBindInfo)); VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SASLSessionInit: sasl error (%d)", dwError ); dwError = _VmDirSASLToLDAPError(dwError); goto cleanup; }
int virNetSASLSessionExtKeySize(virNetSASLSessionPtr sasl, int ssf) { int err; int ret = -1; virObjectLock(sasl); err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf); if (err != SASL_OK) { virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot set external SSF %d (%s)"), err, sasl_errstring(err, NULL, NULL)); goto cleanup; } ret = 0; cleanup: virObjectUnlock(sasl); return ret; }
static int xsasl_cyrus_server_set_security(XSASL_SERVER *xp, const char *sasl_opts_val) { XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp; sasl_security_properties_t sec_props; int sasl_status; /* * Security options. Some information can be found in the sasl.h include * file. */ memset(&sec_props, 0, sizeof(sec_props)); sec_props.min_ssf = 0; sec_props.max_ssf = 0; /* don't allow real SASL * security layer */ if (*sasl_opts_val == 0) { sec_props.security_flags = 0; } else { sec_props.security_flags = xsasl_cyrus_security_parse_opts(sasl_opts_val); if (sec_props.security_flags == 0) { msg_warn("bad per-session SASL security properties"); return (XSASL_AUTH_FAIL); } } sec_props.maxbufsize = 0; sec_props.property_names = 0; sec_props.property_values = 0; if ((sasl_status = sasl_setprop(server->sasl_conn, SASL_SEC_PROPS, &sec_props)) != SASL_OK) { msg_warn("SASL per-connection security setup; %s", xsasl_cyrus_strerror(sasl_status)); return (XSASL_AUTH_FAIL); } return (XSASL_AUTH_OK); }
static int xsasl_cyrus_client_set_security(XSASL_CLIENT *xp, const char *sasl_opts_val) { XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp; sasl_security_properties_t sec_props; int sasl_status; /* * Per-session security properties. XXX This routine is not sufficiently * documented. What is the purpose of all this? */ memset(&sec_props, 0, sizeof(sec_props)); sec_props.min_ssf = 0; sec_props.max_ssf = 0; /* don't allow real SASL * security layer */ if (*sasl_opts_val == 0) { sec_props.security_flags = 0; } else { sec_props.security_flags = xsasl_cyrus_security_parse_opts(sasl_opts_val); if (sec_props.security_flags == 0) { msg_warn("bad per-session SASL security properties"); return (XSASL_AUTH_FAIL); } } sec_props.maxbufsize = 0; sec_props.property_names = 0; sec_props.property_values = 0; if ((sasl_status = sasl_setprop(client->sasl_conn, SASL_SEC_PROPS, &sec_props)) != SASL_OK) { msg_warn("set per-session SASL security properties: %s", xsasl_cyrus_strerror(sasl_status)); return (XSASL_AUTH_FAIL); } return (XSASL_AUTH_OK); }
static int backend_authenticate(struct backend *s, const char *userid, sasl_callback_t *cb, const char **status) { struct protocol_t *prot = s->prot; int r; char *mechlist; sasl_security_properties_t secprops = { 0, 0xFF, PROT_BUFSIZE, 0, NULL, NULL }; /* default secprops */ struct sockaddr_storage saddr_l, saddr_r; char remoteip[60], localip[60]; socklen_t addrsize; int local_cb = 0; char buf[2048], optstr[128], *p; const char *mech_conf, *pass; /* set the IP addresses */ addrsize=sizeof(struct sockaddr_storage); if (getpeername(s->sock, (struct sockaddr *)&saddr_r, &addrsize) != 0) return SASL_FAIL; if(iptostring((struct sockaddr *)&saddr_r, addrsize, remoteip, 60) != 0) return SASL_FAIL; addrsize=sizeof(struct sockaddr_storage); if (getsockname(s->sock, (struct sockaddr *)&saddr_l, &addrsize)!=0) return SASL_FAIL; if(iptostring((struct sockaddr *)&saddr_l, addrsize, localip, 60) != 0) return SASL_FAIL; if (!cb) { local_cb = 1; strlcpy(optstr, s->hostname, sizeof(optstr)); p = strchr(optstr, '.'); if (p) *p = '\0'; strlcat(optstr, "_password", sizeof(optstr)); pass = config_getoverflowstring(optstr, NULL); if(!pass) pass = config_getstring(IMAPOPT_PROXY_PASSWORD); cb = mysasl_callbacks(userid, config_getstring(IMAPOPT_PROXY_AUTHNAME), config_getstring(IMAPOPT_PROXY_REALM), pass); } /* Require proxying if we have an "interesting" userid (authzid) */ r = sasl_client_new(prot->sasl_service, s->hostname, localip, remoteip, cb, (userid && *userid ? SASL_NEED_PROXY : 0) | (prot->sasl_cmd.parse_success ? SASL_SUCCESS_DATA : 0), &s->saslconn); if (r != SASL_OK) goto out; r = sasl_setprop(s->saslconn, SASL_SEC_PROPS, &secprops); if (r != SASL_OK) goto out; /* Get SASL mechanism list. We can force a particular mechanism using a <shorthost>_mechs option */ strcpy(buf, s->hostname); p = strchr(buf, '.'); if (p) *p = '\0'; strcat(buf, "_mechs"); mech_conf = config_getoverflowstring(buf, NULL); if (!mech_conf) { mech_conf = config_getstring(IMAPOPT_FORCE_SASL_CLIENT_MECH); } mechlist = backend_get_cap_params(s, CAPA_AUTH); do { /* If we have a mech_conf, use it */ if (mech_conf && mechlist) { char *conf = xstrdup(mech_conf); char *newmechlist = intersect_mechlists( conf, mechlist ); if ( newmechlist == NULL ) { syslog( LOG_INFO, "%s did not offer %s", s->hostname, mech_conf ); } free(conf); free(mechlist); mechlist = newmechlist; } if (mechlist) { /* we now do the actual SASL exchange */ saslclient(s->saslconn, &prot->sasl_cmd, mechlist, s->in, s->out, &r, status); /* garbage collect */ free(mechlist); mechlist = NULL; } else r = SASL_NOMECH; /* If we don't have a usable mech, do TLS and try again */ } while (r == SASL_NOMECH && CAPA(s, CAPA_STARTTLS) && do_starttls(s) != -1 && (mechlist = backend_get_cap_params(s, CAPA_AUTH))); if (r == SASL_OK) { prot_setsasl(s->in, s->saslconn); prot_setsasl(s->out, s->saslconn); } if (mechlist) free(mechlist); out: /* r == SASL_OK on success */ if (local_cb) free_callbacks(cb); return r; }
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 */ }
/* mutt_sasl_client_new: wrapper for sasl_client_new which also sets various * security properties. If this turns out to be fine for POP too we can * probably stop exporting mutt_sasl_get_callbacks(). */ int mutt_sasl_client_new (CONNECTION * conn, sasl_conn_t ** saslconn) { sasl_security_properties_t secprops; struct sockaddr_storage local, remote; socklen_t size; char iplocalport[IP_PORT_BUFLEN], ipremoteport[IP_PORT_BUFLEN]; const char *service; int rc; if (mutt_sasl_start () != SASL_OK) return -1; switch (conn->account.type) { case M_ACCT_TYPE_IMAP: service = "imap"; break; case M_ACCT_TYPE_POP: service = "pop"; break; default: debug_print (1, ("account type unset\n")); return -1; } size = sizeof (local); if (getsockname (conn->fd, (struct sockaddr *) &local, &size)) { debug_print (1, ("getsockname for local failed\n")); return -1; } else if (iptostring ((struct sockaddr *) &local, size, iplocalport, IP_PORT_BUFLEN) != SASL_OK) { debug_print (1, ("iptostring for local failed\n")); return -1; } size = sizeof (remote); if (getpeername (conn->fd, (struct sockaddr *) &remote, &size)) { debug_print (1, ("getsockname for remote failed\n")); return -1; } else if (iptostring ((struct sockaddr *) &remote, size, ipremoteport, IP_PORT_BUFLEN) != SASL_OK) { debug_print (1, ("iptostring for remote failed\n")); return -1; } debug_print (1, ("local ip: %s, remote ip:%s\n", iplocalport, ipremoteport)); rc = sasl_client_new (service, conn->account.host, iplocalport, ipremoteport, mutt_sasl_get_callbacks (&conn->account), 0, saslconn); if (rc != SASL_OK) { debug_print (1, ("Error allocating SASL connection\n")); return -1; } /*** set sasl IP properties, necessary for use with krb4 ***/ /* Do we need to fail if this fails? I would assume having these unset * would just disable KRB4. Who wrote this code? */ { struct sockaddr_in local, remote; socklen_t size; size = sizeof (local); if (getsockname (conn->fd, (struct sockaddr *) &local, &size)) return -1; size = sizeof (remote); if (getpeername (conn->fd, (struct sockaddr *) &remote, &size)) return -1; #ifdef SASL_IP_LOCAL if (sasl_setprop (*saslconn, SASL_IP_LOCAL, &local) != SASL_OK) { debug_print (1, ("Error setting local IP address\n")); return -1; } #endif #ifdef SASL_IP_REMOTE if (sasl_setprop (*saslconn, SASL_IP_REMOTE, &remote) != SASL_OK) { debug_print (1, ("Error setting remote IP address\n")); return -1; } #endif } /* set security properties. We use NOPLAINTEXT globally, since we can * just fall back to LOGIN in the IMAP case anyway. If that doesn't * work for POP, we can make it a flag or move this code into * imap/auth_sasl.c */ memset (&secprops, 0, sizeof (secprops)); /* Work around a casting bug in the SASL krb4 module */ secprops.max_ssf = 0x7fff; secprops.maxbufsize = M_SASL_MAXBUF; secprops.security_flags |= SASL_SEC_NOPLAINTEXT; if (sasl_setprop (*saslconn, SASL_SEC_PROPS, &secprops) != SASL_OK) { debug_print (1, ("Error setting security properties\n")); return -1; } if (conn->ssf) { debug_print (2, ("External SSF: %d\n", conn->ssf)); if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &(conn->ssf)) != SASL_OK) { debug_print (1, ("Error setting external properties\n")); return -1; } debug_print (2, ("External authentication name: %s\n", conn->account.user)); if (sasl_setprop (*saslconn, SASL_AUTH_EXTERNAL, conn->account.user) != SASL_OK) { debug_print (1, ("Error setting external properties\n")); return -1; } } return 0; }
/* * Initialize SASL and set necessary options */ int init_sasl(isieve_t *obj, int ssf, sasl_callback_t *callbacks) { static int sasl_started = 0; int saslresult = SASL_OK; sasl_security_properties_t *secprops=NULL; socklen_t addrsize=sizeof(struct sockaddr_storage); struct sockaddr_storage saddr_l, saddr_r; char localip[60], remoteip[60]; /* attempt to start sasl */ if(!sasl_started) { saslresult=sasl_client_init(NULL); obj->conn = NULL; sasl_started = 1; } /* Save the callbacks array */ obj->callbacks = callbacks; if (saslresult!=SASL_OK) return -1; addrsize=sizeof(struct sockaddr_storage); if (getpeername(obj->sock,(struct sockaddr *)&saddr_r,&addrsize)!=0) return -1; addrsize=sizeof(struct sockaddr_storage); if (getsockname(obj->sock,(struct sockaddr *)&saddr_l,&addrsize)!=0) return -1; #if 0 /* XXX The following line causes problems with KERBEROS_V4 decoding. * We're not sure why its an issue, but this code isn't used in any of * our other client code (imtest.c, backend.c), so we're removing it. */ /* set the port manually since getsockname is stupid and doesn't */ ((struct sockaddr_in *)&saddr_l)->sin_port = htons(obj->port); #endif if (iptostring((struct sockaddr *)&saddr_r, addrsize, remoteip, 60)) return -1; if (iptostring((struct sockaddr *)&saddr_l, addrsize, localip, 60)) return -1; if(obj->conn) sasl_dispose(&obj->conn); /* client new connection */ saslresult=sasl_client_new(SIEVE_SERVICE_NAME, obj->serverFQDN, localip, remoteip, callbacks, SASL_SUCCESS_DATA, &obj->conn); if (saslresult!=SASL_OK) return -1; /* create a security structure and give it to sasl */ secprops = make_secprops(0, ssf); if (secprops != NULL) { sasl_setprop(obj->conn, SASL_SEC_PROPS, secprops); free(secprops); } return 0; }
static JabberSaslState jabber_auth_start_cyrus(JabberStream *js, xmlnode **reply, char **error) { PurpleAccount *account; const char *clientout = NULL; char *enc_out; unsigned coutlen = 0; sasl_security_properties_t secprops; gboolean again; gboolean plaintext = TRUE; /* Set up security properties and options */ secprops.min_ssf = 0; secprops.security_flags = SASL_SEC_NOANONYMOUS; account = purple_connection_get_account(js->gc); if (!jabber_stream_is_ssl(js)) { secprops.max_ssf = -1; secprops.maxbufsize = 4096; plaintext = purple_account_get_bool(account, "auth_plain_in_clear", FALSE); if (!plaintext) secprops.security_flags |= SASL_SEC_NOPLAINTEXT; } else { secprops.max_ssf = 0; secprops.maxbufsize = 0; plaintext = TRUE; } secprops.property_names = 0; secprops.property_values = 0; do { again = FALSE; js->sasl_state = sasl_client_new("xmpp", js->serverFQDN, NULL, NULL, js->sasl_cb, 0, &js->sasl); if (js->sasl_state==SASL_OK) { sasl_setprop(js->sasl, SASL_SEC_PROPS, &secprops); purple_debug_info("sasl", "Mechs found: %s\n", js->sasl_mechs->str); js->sasl_state = sasl_client_start(js->sasl, js->sasl_mechs->str, NULL, &clientout, &coutlen, &js->current_mech); } switch (js->sasl_state) { /* Success */ case SASL_OK: case SASL_CONTINUE: break; case SASL_NOMECH: /* No mechanisms have offered to help */ /* Firstly, if we don't have a password try * to get one */ if (!purple_account_get_password(account)) { purple_account_request_password(account, G_CALLBACK(auth_pass_cb), G_CALLBACK(auth_no_pass_cb), js->gc); return JABBER_SASL_STATE_CONTINUE; /* If we've got a password, but aren't sending * it in plaintext, see if we can turn on * plaintext auth */ /* XXX Should we just check for PLAIN/LOGIN being offered mechanisms? */ } else if (!plaintext) { char *msg = g_strdup_printf(_("%s may require plaintext authentication over an unencrypted connection. Allow this and continue authentication?"), purple_account_get_username(account)); purple_request_yes_no(js->gc, _("Plaintext Authentication"), _("Plaintext Authentication"), msg, 1, account, NULL, NULL, account, allow_cyrus_plaintext_auth, disallow_plaintext_auth); g_free(msg); return JABBER_SASL_STATE_CONTINUE; } else js->auth_fail_count++; if (js->auth_fail_count == 1 && (js->sasl_mechs->str && g_str_equal(js->sasl_mechs->str, "GSSAPI"))) { /* If we tried GSSAPI first, it failed, and it was the only method we had to try, try jabber:iq:auth * for compatibility with iChat 10.5 Server and other jabberd based servers. * * iChat Server 10.5 and certain other corporate servers offer SASL GSSAPI by default, which is often * not configured on the client side, and expects a fallback to jabber:iq:auth when it (predictably) fails. * * Note: xep-0078 points out that using jabber:iq:auth after a sasl failure is wrong. However, * I believe this refers to actual authentication failure, not a simple lack of concordant mechanisms. * Doing otherwise means that simply compiling with SASL support renders the client unable to connect to servers * which would connect without issue otherwise. -evands */ js->auth_mech = NULL; jabber_auth_start_old(js); return JABBER_SASL_STATE_CONTINUE; } break; /* Fatal errors. Give up and go home */ case SASL_BADPARAM: case SASL_NOMEM: *error = g_strdup(_("SASL authentication failed")); break; /* For everything else, fail the mechanism and try again */ default: purple_debug_info("sasl", "sasl_state is %d, failing the mech and trying again\n", js->sasl_state); js->auth_fail_count++; /* * DAA: is this right? * The manpage says that "mech" will contain the chosen mechanism on success. * Presumably, if we get here that isn't the case and we shouldn't try again? * I suspect that this never happens. */ /* * SXW: Yes, this is right. What this handles is the situation where a * mechanism, say GSSAPI, is tried. If that mechanism fails, it may be * due to mechanism specific issues, so we want to try one of the other * supported mechanisms. This code handles that case */ if (js->current_mech && *js->current_mech) { char *pos; if ((pos = strstr(js->sasl_mechs->str, js->current_mech))) { g_string_erase(js->sasl_mechs, pos-js->sasl_mechs->str, strlen(js->current_mech)); } /* Remove space which separated this mech from the next */ if ((js->sasl_mechs->str)[0] == ' ') { g_string_erase(js->sasl_mechs, 0, 1); } again = TRUE; } sasl_dispose(&js->sasl); } } while (again); if (js->sasl_state == SASL_CONTINUE || js->sasl_state == SASL_OK) { xmlnode *auth = xmlnode_new("auth"); xmlnode_set_namespace(auth, NS_XMPP_SASL); xmlnode_set_attrib(auth, "mechanism", js->current_mech); xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); if (clientout) { if (coutlen == 0) { xmlnode_insert_data(auth, "=", -1); } else { enc_out = purple_base64_encode((unsigned char*)clientout, coutlen); xmlnode_insert_data(auth, enc_out, -1); g_free(enc_out); } } *reply = auth; return JABBER_SASL_STATE_CONTINUE; } else { return JABBER_SASL_STATE_FAIL; } }
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(); }
/* mutt_sasl_client_new: wrapper for sasl_client_new which also sets various * security properties. If this turns out to be fine for POP too we can * probably stop exporting mutt_sasl_get_callbacks(). */ int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn) { sasl_security_properties_t secprops; struct sockaddr_storage local, remote; socklen_t size; char iplocalport[IP_PORT_BUFLEN], ipremoteport[IP_PORT_BUFLEN]; char* plp = NULL; char* prp = NULL; const char* service; int rc; if (mutt_sasl_start () != SASL_OK) return -1; switch (conn->account.type) { case M_ACCT_TYPE_IMAP: service = "imap"; break; case M_ACCT_TYPE_POP: service = "pop"; break; case M_ACCT_TYPE_SMTP: service = "smtp"; break; default: mutt_error (_("Unknown SASL profile")); return -1; } size = sizeof (local); if (!getsockname (conn->fd, (struct sockaddr *)&local, &size)) { if (!iptostring((struct sockaddr *)&local, size, iplocalport, IP_PORT_BUFLEN) != SASL_OK) plp = iplocalport; else dprint (2, (debugfile, "SASL failed to parse local IP address\n")); } else dprint (2, (debugfile, "SASL failed to get local IP address\n")); size = sizeof (remote); if (!getpeername (conn->fd, (struct sockaddr *)&remote, &size)){ if (!iptostring((struct sockaddr *)&remote, size, ipremoteport, IP_PORT_BUFLEN) != SASL_OK) prp = ipremoteport; else dprint (2, (debugfile, "SASL failed to parse remote IP address\n")); } else dprint (2, (debugfile, "SASL failed to get remote IP address\n")); dprint (2, (debugfile, "SASL local ip: %s, remote ip:%s\n", NONULL(plp), NONULL(prp))); rc = sasl_client_new (service, conn->account.host, plp, prp, mutt_sasl_get_callbacks (&conn->account), 0, saslconn); if (rc != SASL_OK) { mutt_error (_("Error allocating SASL connection")); return -1; } memset (&secprops, 0, sizeof (secprops)); /* Work around a casting bug in the SASL krb4 module */ secprops.max_ssf = 0x7fff; secprops.maxbufsize = M_SASL_MAXBUF; if (sasl_setprop (*saslconn, SASL_SEC_PROPS, &secprops) != SASL_OK) { mutt_error (_("Error setting SASL security properties")); return -1; } if (conn->ssf) { /* I'm not sure this actually has an effect, at least with SASLv2 */ dprint (2, (debugfile, "External SSF: %d\n", conn->ssf)); if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &(conn->ssf)) != SASL_OK) { mutt_error (_("Error setting SASL external security strength")); return -1; } } if (conn->account.user[0]) { dprint (2, (debugfile, "External authentication name: %s\n", conn->account.user)); if (sasl_setprop (*saslconn, SASL_AUTH_EXTERNAL, conn->account.user) != SASL_OK) { mutt_error (_("Error setting SASL external user name")); return -1; } } return 0; }
svn_error_t *cyrus_auth_request(svn_ra_svn_conn_t *conn, apr_pool_t *pool, server_baton_t *b, enum access_type required, svn_boolean_t needs_username) { sasl_conn_t *sasl_ctx; apr_pool_t *subpool; apr_status_t apr_err; const char *localaddrport = NULL, *remoteaddrport = NULL; const char *mechlist, *val; char hostname[APRMAXHOSTLEN + 1]; sasl_security_properties_t secprops; svn_boolean_t success, no_anonymous; int mech_count, result = SASL_OK; SVN_ERR(svn_ra_svn__get_addresses(&localaddrport, &remoteaddrport, conn, pool)); apr_err = apr_gethostname(hostname, sizeof(hostname), pool); if (apr_err) { svn_error_t *err = svn_error_wrap_apr(apr_err, _("Can't get hostname")); SVN_ERR(write_failure(conn, pool, &err)); return svn_ra_svn_flush(conn, pool); } /* Create a SASL context. SASL_SUCCESS_DATA tells SASL that the protocol supports sending data along with the final "success" message. */ result = sasl_server_new(SVN_RA_SVN_SASL_NAME, hostname, b->realm, localaddrport, remoteaddrport, NULL, SASL_SUCCESS_DATA, &sasl_ctx); if (result != SASL_OK) { svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL, sasl_errstring(result, NULL, NULL)); SVN_ERR(write_failure(conn, pool, &err)); return svn_ra_svn_flush(conn, pool); } /* Make sure the context is always destroyed. */ apr_pool_cleanup_register(b->pool, sasl_ctx, sasl_dispose_cb, apr_pool_cleanup_null); /* Initialize security properties. */ svn_ra_svn__default_secprops(&secprops); /* Don't allow ANONYMOUS if a username is required. */ no_anonymous = needs_username || get_access(b, UNAUTHENTICATED) < required; if (no_anonymous) secprops.security_flags |= SASL_SEC_NOANONYMOUS; svn_config_get(b->cfg, &val, SVN_CONFIG_SECTION_SASL, SVN_CONFIG_OPTION_MIN_SSF, "0"); SVN_ERR(svn_cstring_atoui(&secprops.min_ssf, val)); svn_config_get(b->cfg, &val, SVN_CONFIG_SECTION_SASL, SVN_CONFIG_OPTION_MAX_SSF, "256"); SVN_ERR(svn_cstring_atoui(&secprops.max_ssf, val)); /* Set security properties. */ result = sasl_setprop(sasl_ctx, SASL_SEC_PROPS, &secprops); if (result != SASL_OK) return fail_cmd(conn, pool, sasl_ctx); /* SASL needs to know if we are externally authenticated. */ if (b->tunnel_user) result = sasl_setprop(sasl_ctx, SASL_AUTH_EXTERNAL, b->tunnel_user); if (result != SASL_OK) return fail_cmd(conn, pool, sasl_ctx); /* Get the list of mechanisms. */ result = sasl_listmech(sasl_ctx, NULL, NULL, " ", NULL, &mechlist, NULL, &mech_count); if (result != SASL_OK) return fail_cmd(conn, pool, sasl_ctx); if (mech_count == 0) { svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL, _("Could not obtain the list" " of SASL mechanisms")); SVN_ERR(write_failure(conn, pool, &err)); return svn_ra_svn_flush(conn, pool); } /* Send the list of mechanisms and the realm to the client. */ SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "(w)c", mechlist, b->realm)); /* The main authentication loop. */ subpool = svn_pool_create(pool); do { svn_pool_clear(subpool); SVN_ERR(try_auth(conn, sasl_ctx, subpool, b, &success)); } while (!success); svn_pool_destroy(subpool); SVN_ERR(svn_ra_svn__enable_sasl_encryption(conn, sasl_ctx, pool)); if (no_anonymous) { char *p; const void *user; /* Get the authenticated username. */ result = sasl_getprop(sasl_ctx, SASL_USERNAME, &user); if (result != SASL_OK) return fail_cmd(conn, pool, sasl_ctx); if ((p = strchr(user, '@')) != NULL) { /* Drop the realm part. */ b->user = apr_pstrndup(b->pool, user, p - (const char *)user); } else { svn_error_t *err; err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL, _("Couldn't obtain the authenticated" " username")); SVN_ERR(write_failure(conn, pool, &err)); return svn_ra_svn_flush(conn, pool); } } return SVN_NO_ERROR; }
POP3_SASL_STATE_E Pop3SaslWrapper::SaslInit(const Pop3SaslInfo_t& sasl_data) { if(sasl_data.user_name == "") { return POP3_SASL_ERROR; } this->sasl_data = sasl_data; //Initialize the callbacks /*sasl_callback[0].id = SASL_CB_GETREALM; sasl_callback[0].proc = (int (*)())getrealm_func; sasl_callback[0].context = this;*/ sasl_callback[0].id = SASL_CB_USER; sasl_callback[0].proc = (int (*)())getauthname_func; sasl_callback[0].context = this; sasl_callback[1].id = SASL_CB_AUTHNAME; sasl_callback[1].proc = (int (*)())getauthname_func; sasl_callback[1].context = this; sasl_callback[2].id = SASL_CB_PASS; sasl_callback[2].proc = (int (*)())getsecret_func; sasl_callback[2].context = this; sasl_callback[3].id = SASL_CB_CANON_USER; sasl_callback[3].proc = (int (*)())getcannonical_user_func; sasl_callback[3].context = this; sasl_callback[4].id = SASL_CB_LIST_END; sasl_callback[4].proc = 0; sasl_callback[4].context = this; //Initialize the secret //If the allocated memory does not include length of password, the program results in memory corruption secret = (sasl_secret_t*) malloc(sizeof(sasl_secret_t)+sasl_data.user_pass.length()); if(secret == 0) { //Error POP3_SASL_DEBUG("SASL-Error: Memory allocation failed\n"); return POP3_SASL_ERROR; } secret->len = sasl_data.user_pass.length(); memcpy(secret->data, sasl_data.user_pass.c_str(), secret->len); int sasl_result = sasl_client_init(0); if(sasl_result != SASL_OK) { //Error POP3_SASL_DEBUG("SASL-Error 2\n"); return POP3_SASL_ERROR; } sasl_result = sasl_client_new(sasl_data.service.c_str(), sasl_data.hostname.c_str(), NULL, NULL, sasl_callback, 0, &conn); if(sasl_result != SASL_OK) { //Error POP3_SASL_DEBUG("SASL-Error 3\n"); return POP3_SASL_ERROR; } memset(&secprops, 0, sizeof(secprops)); secprops.maxbufsize = 8192; //TODO: Needs change secprops.max_ssf = UINT_MAX; sasl_result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops); if(sasl_result != SASL_OK) { POP3_SASL_DEBUG("sasl_setprop failed\n"); return POP3_SASL_ERROR; } return POP3_SASL_OK; }
bool reds_sasl_start_auth(RedsStream *stream, AsyncReadDone read_cb, void *opaque) { const char *mechlist = NULL; sasl_security_properties_t secprops; int err; char *localAddr, *remoteAddr; int mechlistlen; RedsSASL *sasl = &stream->priv->sasl; if (!(localAddr = reds_stream_get_local_address(stream))) { goto error; } if (!(remoteAddr = reds_stream_get_remote_address(stream))) { free(localAddr); goto error; } err = sasl_server_new("spice", NULL, /* FQDN - just delegates to gethostname */ NULL, /* User realm */ localAddr, remoteAddr, NULL, /* Callbacks, not needed */ SASL_SUCCESS_DATA, &sasl->conn); free(localAddr); free(remoteAddr); localAddr = remoteAddr = NULL; if (err != SASL_OK) { spice_warning("sasl context setup failed %d (%s)", err, sasl_errstring(err, NULL, NULL)); sasl->conn = NULL; goto error; } /* Inform SASL that we've got an external SSF layer from TLS */ if (stream->priv->ssl) { sasl_ssf_t ssf; ssf = SSL_get_cipher_bits(stream->priv->ssl, NULL); err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf); if (err != SASL_OK) { spice_warning("cannot set SASL external SSF %d (%s)", err, sasl_errstring(err, NULL, NULL)); goto error_dispose; } } else { sasl->wantSSF = 1; } memset(&secprops, 0, sizeof secprops); /* Inform SASL that we've got an external SSF layer from TLS */ if (stream->priv->ssl) { /* If we've got TLS (or UNIX domain sock), we don't care about SSF */ secprops.min_ssf = 0; secprops.max_ssf = 0; secprops.maxbufsize = 8192; secprops.security_flags = 0; } else { /* Plain TCP, better get an SSF layer */ secprops.min_ssf = 56; /* Good enough to require kerberos */ secprops.max_ssf = 100000; /* Arbitrary big number */ secprops.maxbufsize = 8192; /* Forbid any anonymous or trivially crackable auth */ secprops.security_flags = SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; } err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops); if (err != SASL_OK) { spice_warning("cannot set SASL security props %d (%s)", err, sasl_errstring(err, NULL, NULL)); goto error_dispose; } err = sasl_listmech(sasl->conn, NULL, /* Don't need to set user */ "", /* Prefix */ ",", /* Separator */ "", /* Suffix */ &mechlist, NULL, NULL); if (err != SASL_OK || mechlist == NULL) { spice_warning("cannot list SASL mechanisms %d (%s)", err, sasl_errdetail(sasl->conn)); goto error_dispose; } spice_debug("Available mechanisms for client: '%s'", mechlist); sasl->mechlist = spice_strdup(mechlist); mechlistlen = strlen(mechlist); if (!reds_stream_write_all(stream, &mechlistlen, sizeof(uint32_t)) || !reds_stream_write_all(stream, sasl->mechlist, mechlistlen)) { spice_warning("SASL mechanisms write error"); goto error; } spice_debug("Wait for client mechname length"); reds_stream_async_read(stream, (uint8_t *)&sasl->len, sizeof(uint32_t), read_cb, opaque); return true; error_dispose: sasl_dispose(&sasl->conn); sasl->conn = NULL; error: return false; }
void start_auth_sasl(VncState *vs) { const char *mechlist = NULL; sasl_security_properties_t secprops; int err; char *localAddr, *remoteAddr; int mechlistlen; VNC_DEBUG("Initialize SASL auth %p\n", vs->ioc); /* Get local & remote client addresses in form IPADDR;PORT */ localAddr = vnc_socket_ip_addr_string(vs->sioc, true, NULL); if (!localAddr) { goto authabort; } remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, NULL); if (!remoteAddr) { g_free(localAddr); goto authabort; } err = sasl_server_new("vnc", NULL, /* FQDN - just delegates to gethostname */ NULL, /* User realm */ localAddr, remoteAddr, NULL, /* Callbacks, not needed */ SASL_SUCCESS_DATA, &vs->sasl.conn); g_free(localAddr); g_free(remoteAddr); localAddr = remoteAddr = NULL; if (err != SASL_OK) { VNC_DEBUG("sasl context setup failed %d (%s)", err, sasl_errstring(err, NULL, NULL)); vs->sasl.conn = NULL; goto authabort; } /* Inform SASL that we've got an external SSF layer from TLS/x509 */ if (vs->auth == VNC_AUTH_VENCRYPT && vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) { Error *local_err = NULL; int keysize; sasl_ssf_t ssf; keysize = qcrypto_tls_session_get_key_size(vs->tls, &local_err); if (keysize < 0) { VNC_DEBUG("cannot TLS get cipher size: %s\n", error_get_pretty(local_err)); error_free(local_err); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } ssf = keysize * CHAR_BIT; /* tls key size is bytes, sasl wants bits */ err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf); if (err != SASL_OK) { VNC_DEBUG("cannot set SASL external SSF %d (%s)\n", err, sasl_errstring(err, NULL, NULL)); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } } else { vs->sasl.wantSSF = 1; } memset (&secprops, 0, sizeof secprops); /* Inform SASL that we've got an external SSF layer from TLS. * * Disable SSF, if using TLS+x509+SASL only. TLS without x509 * is not sufficiently strong */ if (vs->vd->is_unix || (vs->auth == VNC_AUTH_VENCRYPT && vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)) { /* If we've got TLS or UNIX domain sock, we don't care about SSF */ secprops.min_ssf = 0; secprops.max_ssf = 0; secprops.maxbufsize = 8192; secprops.security_flags = 0; } else { /* Plain TCP, better get an SSF layer */ secprops.min_ssf = 56; /* Good enough to require kerberos */ secprops.max_ssf = 100000; /* Arbitrary big number */ secprops.maxbufsize = 8192; /* Forbid any anonymous or trivially crackable auth */ secprops.security_flags = SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; } err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops); if (err != SASL_OK) { VNC_DEBUG("cannot set SASL security props %d (%s)\n", err, sasl_errstring(err, NULL, NULL)); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } err = sasl_listmech(vs->sasl.conn, NULL, /* Don't need to set user */ "", /* Prefix */ ",", /* Separator */ "", /* Suffix */ &mechlist, NULL, NULL); if (err != SASL_OK) { VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n", err, sasl_errdetail(vs->sasl.conn)); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist); vs->sasl.mechlist = g_strdup(mechlist); mechlistlen = strlen(mechlist); vnc_write_u32(vs, mechlistlen); vnc_write(vs, mechlist, mechlistlen); vnc_flush(vs); VNC_DEBUG("Wait for client mechname length\n"); vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4); return; authabort: vnc_client_error(vs); }
static int login(struct backend *s, const char *userid, sasl_callback_t *cb, const char **status, int noauth __attribute__((unused))) { int r = 0; socklen_t addrsize; struct sockaddr_storage saddr_l, saddr_r; char remoteip[60], localip[60]; static struct buf buf = BUF_INITIALIZER; sasl_security_properties_t secprops = { 0, 0xFF, PROT_BUFSIZE, 0, NULL, NULL }; /* default secprops */ const char *mech_conf, *pass, *clientout = NULL; struct auth_scheme_t *scheme = NULL; unsigned need_tls = 0, tls_done = 0, auth_done = 0, clientoutlen; hdrcache_t hdrs = NULL; if (status) *status = NULL; /* set the IP addresses */ addrsize = sizeof(struct sockaddr_storage); if (getpeername(s->sock, (struct sockaddr *) &saddr_r, &addrsize) || iptostring((struct sockaddr *) &saddr_r, addrsize, remoteip, 60)) { if (status) *status = "Failed to get remote IP address"; return SASL_FAIL; } addrsize = sizeof(struct sockaddr_storage); if (getsockname(s->sock, (struct sockaddr *) &saddr_l, &addrsize) || iptostring((struct sockaddr *) &saddr_l, addrsize, localip, 60)) { if (status) *status = "Failed to get local IP address"; return SASL_FAIL; } /* Create callbacks, if necessary */ if (!cb) { buf_setmap(&buf, s->hostname, strcspn(s->hostname, ".")); buf_appendcstr(&buf, "_password"); pass = config_getoverflowstring(buf_cstring(&buf), NULL); if (!pass) pass = config_getstring(IMAPOPT_PROXY_PASSWORD); cb = mysasl_callbacks(NULL, /* userid */ config_getstring(IMAPOPT_PROXY_AUTHNAME), config_getstring(IMAPOPT_PROXY_REALM), pass); s->sasl_cb = cb; } /* Create SASL context */ r = sasl_client_new(s->prot->sasl_service, s->hostname, localip, remoteip, cb, SASL_USAGE_FLAGS, &s->saslconn); if (r != SASL_OK) goto done; r = sasl_setprop(s->saslconn, SASL_SEC_PROPS, &secprops); if (r != SASL_OK) goto done; /* Get SASL mechanism list. We can force a particular mechanism using a <shorthost>_mechs option */ buf_setmap(&buf, s->hostname, strcspn(s->hostname, ".")); buf_appendcstr(&buf, "_mechs"); if (!(mech_conf = config_getoverflowstring(buf_cstring(&buf), NULL))) { mech_conf = config_getstring(IMAPOPT_FORCE_SASL_CLIENT_MECH); } do { unsigned code; const char **hdr, *errstr, *serverin; char base64[BASE64_BUF_SIZE+1]; unsigned int serverinlen; struct body_t resp_body; #ifdef SASL_HTTP_REQUEST sasl_http_request_t httpreq = { "OPTIONS", /* Method */ "*", /* URI */ (u_char *) "", /* Empty body */ 0, /* Zero-length body */ 0 }; /* Persistent cxn? */ #endif /* Base64 encode any client response, if necessary */ if (clientout && scheme && (scheme->flags & AUTH_BASE64)) { r = sasl_encode64(clientout, clientoutlen, base64, BASE64_BUF_SIZE, &clientoutlen); if (r != SASL_OK) break; clientout = base64; } /* Send Authorization and/or Upgrade request to server */ prot_puts(s->out, "OPTIONS * HTTP/1.1\r\n"); prot_printf(s->out, "Host: %s\r\n", s->hostname); prot_printf(s->out, "User-Agent: %s\r\n", buf_cstring(&serverinfo)); if (scheme) { prot_printf(s->out, "Authorization: %s %s\r\n", scheme->name, clientout ? clientout : ""); prot_printf(s->out, "Authorize-As: %s\r\n", userid ? userid : "anonymous"); } else { prot_printf(s->out, "Upgrade: %s\r\n", TLS_VERSION); if (need_tls) { prot_puts(s->out, "Connection: Upgrade\r\n"); need_tls = 0; } prot_puts(s->out, "Authorization: \r\n"); } prot_puts(s->out, "\r\n"); prot_flush(s->out); serverin = clientout = NULL; serverinlen = clientoutlen = 0; /* Read response(s) from backend until final response or error */ do { resp_body.flags = BODY_DISCARD; r = http_read_response(s, METH_OPTIONS, &code, NULL, &hdrs, &resp_body, &errstr); if (r) { if (status) *status = errstr; break; } if (code == 101) { /* Switching Protocols */ if (tls_done) { r = HTTP_BAD_GATEWAY; if (status) *status = "TLS already active"; break; } else if (backend_starttls(s, NULL, NULL, NULL)) { r = HTTP_SERVER_ERROR; if (status) *status = "Unable to start TLS"; break; } else tls_done = 1; } } while (code < 200); switch (code) { default: /* Failure */ if (!r) { r = HTTP_BAD_GATEWAY; if (status) { buf_reset(&buf); buf_printf(&buf, "Unexpected status code from backend: %u", code); *status = buf_cstring(&buf); } } break; case 426: /* Upgrade Required */ if (tls_done) { r = HTTP_BAD_GATEWAY; if (status) *status = "TLS already active"; } else need_tls = 1; break; case 200: /* OK */ if (scheme->recv_success && (serverin = scheme->recv_success(hdrs))) { /* Process success data */ serverinlen = strlen(serverin); goto challenge; } break; case 401: /* Unauthorized */ if (auth_done) { r = SASL_BADAUTH; break; } if (!serverin) { int i = 0; hdr = spool_getheader(hdrs, "WWW-Authenticate"); if (!scheme) { unsigned avail_auth_schemes = 0; const char *mech = NULL; size_t len; /* Compare authentication schemes offered in * WWW-Authenticate header(s) to what we support */ buf_reset(&buf); for (i = 0; hdr && hdr[i]; i++) { len = strcspn(hdr[i], " "); for (scheme = auth_schemes; scheme->name; scheme++) { if (!strncmp(scheme->name, hdr[i], len) && !((scheme->flags & AUTH_NEED_PERSIST) && (resp_body.flags & BODY_CLOSE))) { /* Tag the scheme as available */ avail_auth_schemes |= (1 << scheme->idx); /* Add SASL-based schemes to SASL mech list */ if (scheme->saslmech) { if (buf_len(&buf)) buf_putc(&buf, ' '); buf_appendcstr(&buf, scheme->saslmech); } break; } } } /* If we have a mech_conf, use it */ if (mech_conf && buf_len(&buf)) { char *conf = xstrdup(mech_conf); char *newmechlist = intersect_mechlists(conf, (char *) buf_cstring(&buf)); if (newmechlist) { buf_setcstr(&buf, newmechlist); free(newmechlist); } else { syslog(LOG_DEBUG, "%s did not offer %s", s->hostname, mech_conf); buf_reset(&buf); } free(conf); } #ifdef SASL_HTTP_REQUEST /* Set HTTP request as specified above (REQUIRED) */ httpreq.non_persist = (resp_body.flags & BODY_CLOSE); sasl_setprop(s->saslconn, SASL_HTTP_REQUEST, &httpreq); #endif /* Try to start SASL exchange using available mechs */ r = sasl_client_start(s->saslconn, buf_cstring(&buf), NULL, /* no prompts */ NULL, NULL, /* no initial resp */ &mech); if (mech) { /* Find auth scheme associated with chosen SASL mech */ for (scheme = auth_schemes; scheme->name; scheme++) { if (scheme->saslmech && !strcmp(scheme->saslmech, mech)) break; } } else { /* No matching SASL mechs - try Basic */ scheme = &auth_schemes[AUTH_BASIC]; if (!(avail_auth_schemes & (1 << scheme->idx))) { need_tls = !tls_done; break; /* case 401 */ } } /* Find the associated WWW-Authenticate header */ for (i = 0; hdr && hdr[i]; i++) { len = strcspn(hdr[i], " "); if (!strncmp(scheme->name, hdr[i], len)) break; } } /* Get server challenge, if any */ if (hdr) { const char *p = strchr(hdr[i], ' '); serverin = p ? ++p : ""; serverinlen = strlen(serverin); } } challenge: if (serverin) { /* Perform the next step in the auth exchange */ if (scheme->idx == AUTH_BASIC) { /* Don't care about "realm" in server challenge */ const char *authid = callback_getdata(s->saslconn, cb, SASL_CB_AUTHNAME); pass = callback_getdata(s->saslconn, cb, SASL_CB_PASS); buf_reset(&buf); buf_printf(&buf, "%s:%s", authid, pass); clientout = buf_cstring(&buf); clientoutlen = buf_len(&buf); auth_done = 1; } else { /* Base64 decode any server challenge, if necessary */ if (serverin && (scheme->flags & AUTH_BASE64)) { r = sasl_decode64(serverin, serverinlen, base64, BASE64_BUF_SIZE, &serverinlen); if (r != SASL_OK) break; /* case 401 */ serverin = base64; } /* SASL mech (Digest, Negotiate, NTLM) */ r = sasl_client_step(s->saslconn, serverin, serverinlen, NULL, /* no prompts */ &clientout, &clientoutlen); if (r == SASL_OK) auth_done = 1; } } break; /* case 401 */ } } while (need_tls || clientout); done: if (hdrs) spool_free_hdrcache(hdrs); if (r && status && !*status) *status = sasl_errstring(r, NULL, NULL); return r; }