void init_sasl(void) { #ifdef ENABLE_SASL_PWDB memcached_sasl_pwdb = getenv("MEMCACHED_SASL_PWDB"); if (memcached_sasl_pwdb == NULL) { if (settings.verbose) { fprintf(stderr, "INFO: MEMCACHED_SASL_PWDB not specified. " "Internal passwd database disabled\n"); } sasl_callbacks[0].id = SASL_CB_LIST_END; sasl_callbacks[0].proc = NULL; } #endif memset(my_sasl_hostname, 0, sizeof(my_sasl_hostname)); if (gethostname(my_sasl_hostname, sizeof(my_sasl_hostname)-1) == -1) { if (settings.verbose) { fprintf(stderr, "Error discovering hostname for SASL\n"); } my_sasl_hostname[0] = '\0'; } if (sasl_server_init(sasl_callbacks, "memcached") != SASL_OK) { fprintf(stderr, "Error initializing sasl.\n"); exit(EXIT_FAILURE); } else { if (settings.verbose) { fprintf(stderr, "Initialized SASL.\n"); } } }
virtual bool OnLoad(const CString& sArgs, CString& sMessage) { VCString vsChans; VCString::const_iterator it; sArgs.Split(" ", vsChans, false); for (it = vsChans.begin(); it != vsChans.end(); ++it) { if (it->StrCmp("saslauthd") || it->StrCmp("auxprop")) { method += *it + " "; } else { CUtils::PrintError("Ignoring invalid SASL pwcheck method: " + *it); sMessage = "Ignored invalid SASL pwcheck method"; } } method.TrimRight(); if (method.empty()) { sMessage = "Need a pwcheck method as argument (saslauthd, auxprop)"; return false; } if (sasl_server_init(NULL, NULL) != SASL_OK) { sMessage = "SASL Could Not Be Initialized - Halting Startup"; return false; } return true; }
/* * cyrussasl.server_init("appname") * * appname: the name of this application, from SASL's perspective. * * This function does not return any values. On failure, it will throw an * error. */ static int cyrussasl_sasl_server_init(lua_State *l) { const char *appname; int numargs = lua_gettop(l); int err; if (numargs != 1) { lua_pushstring(l, "usage: cyrussasl.server_init(appname)"); lua_error(l); return 0; } appname = tostring(l, 1); err = sasl_server_init( NULL, /* Global callbacks */ appname ); if (err != SASL_OK) { lua_pushstring(l, "sasl_server_init failed"); lua_error(l); return 0; } return 0; }
virtual bool OnLoad(const CString& sArgs, CString& sMessage) { VCString vsArgs; VCString::const_iterator it; sArgs.Split(" ", vsArgs, false); for (it = vsArgs.begin(); it != vsArgs.end(); ++it) { if (it->Equals("saslauthd") || it->Equals("auxprop")) { m_sMethod += *it + " "; } else { CUtils::PrintError("Ignoring invalid SASL pwcheck method: " + *it); sMessage = "Ignored invalid SASL pwcheck method"; } } m_sMethod.TrimRight(); if (m_sMethod.empty()) { sMessage = "Need a pwcheck method as argument (saslauthd, auxprop)"; return false; } if (sasl_server_init(NULL, NULL) != SASL_OK) { sMessage = "SASL Could Not Be Initialized - Halting Startup"; return false; } m_cbs[0].id = SASL_CB_GETOPT; m_cbs[0].proc = reinterpret_cast<int(*)()>(CSASLAuthMod::getopt); m_cbs[0].context = this; m_cbs[1].id = SASL_CB_LIST_END; m_cbs[1].proc = NULL; m_cbs[1].context = NULL; return true; }
EXPORTED void global_sasl_init(int client, int server, const sasl_callback_t *callbacks) { static int called_already = 0; assert(client || server); assert(!called_already); called_already = 1; /* set the SASL allocation functions */ sasl_set_alloc((sasl_malloc_t *) &xmalloc, (sasl_calloc_t *) &xcalloc, (sasl_realloc_t *) &xrealloc, (sasl_free_t *) &free); /* set the SASL mutex functions */ sasl_set_mutex((sasl_mutex_alloc_t *) &cyrus_mutex_alloc, (sasl_mutex_lock_t *) &cyrus_mutex_lock, (sasl_mutex_unlock_t *) &cyrus_mutex_unlock, (sasl_mutex_free_t *) &cyrus_mutex_free); if(client && sasl_client_init(callbacks)) { fatal("could not init sasl (client)", EC_SOFTWARE); } if(server && sasl_server_init(callbacks, "Cyrus")) { fatal("could not init sasl (server)", EC_SOFTWARE); } }
virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitelist) { virNetSASLContextPtr ctxt; int err; err = sasl_server_init(NULL, "libvirt"); if (err != SASL_OK) { virNetError(VIR_ERR_AUTH_FAILED, _("failed to initialize SASL library: %d (%s)"), err, sasl_errstring(err, NULL, NULL)); return NULL; } if (VIR_ALLOC(ctxt) < 0) { virReportOOMError(); return NULL; } if (virMutexInit(&ctxt->lock) < 0) { virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("Failed to initialized mutex")); VIR_FREE(ctxt); return NULL; } ctxt->usernameWhitelist = usernameWhitelist; ctxt->refs = 1; return ctxt; }
static svn_error_t *initialize(void *baton, apr_pool_t *pool) { int result; SVN_ERR(svn_ra_svn__sasl_common_init(pool)); /* The second parameter tells SASL to look for a configuration file named subversion.conf. */ result = sasl_server_init(callbacks, SVN_RA_SVN_SASL_NAME); if (result != SASL_OK) { svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL, sasl_errstring(result, NULL, NULL)); return svn_error_quick_wrap(err, _("Could not initialize the SASL library")); } return SVN_NO_ERROR; }
bool pni_init_server(pn_transport_t* transport) { pni_sasl_t *sasl = transport->sasl; int result; sasl_conn_t *cyrus_conn = NULL; do { if (sasl->config_dir) { result = sasl_set_path(SASL_PATH_TYPE_CONFIG, sasl->config_dir); if (result!=SASL_OK) break; } result = sasl_server_init(NULL, sasl->config_name ? sasl->config_name : "proton-server"); if (result!=SASL_OK) break; result = sasl_server_new(amqp_service, NULL, NULL, NULL, NULL, NULL, 0, &cyrus_conn); if (result!=SASL_OK) break; sasl->impl_context = cyrus_conn; sasl_security_properties_t secprops = {0}; secprops.security_flags = ( sasl->allow_insecure_mechs ? 0 : SASL_SEC_NOPLAINTEXT ) | ( transport->auth_required ? SASL_SEC_NOANONYMOUS : 0 ) ; secprops.min_ssf = 0; secprops.max_ssf = 2048; secprops.maxbufsize = PN_SASL_MAX_BUFFSIZE; result = sasl_setprop(cyrus_conn, SASL_SEC_PROPS, &secprops); if (result!=SASL_OK) break; sasl_ssf_t ssf = sasl->external_ssf; result = sasl_setprop(cyrus_conn, SASL_SSF_EXTERNAL, &ssf); if (result!=SASL_OK) break; const char *extid = sasl->external_auth; if (extid) { result = sasl_setprop(cyrus_conn, SASL_AUTH_EXTERNAL, extid); } } while (false); cyrus_conn = (sasl_conn_t*) sasl->impl_context; return pni_check_sasl_result(cyrus_conn, result, transport); }
bool serverStart(const QString &realm, QStringList *mechlist, const QString &name) { resetState(); g->appname = name; if(!g->server_init) { sasl_server_init(NULL, QFile::encodeName(g->appname)); g->server_init = true; } callbacks = new sasl_callback_t[2]; callbacks[0].id = SASL_CB_PROXY_POLICY; callbacks[0].proc = (int(*)())scb_checkauth; callbacks[0].context = this; callbacks[1].id = SASL_CB_LIST_END; callbacks[1].proc = 0; callbacks[1].context = 0; int r = sasl_server_new(service.toLatin1().data(), host.toLatin1().data(), realm.toLatin1().data(), localAddr.isEmpty() ? 0 : localAddr.toLatin1().data(), remoteAddr.isEmpty() ? 0 : remoteAddr.toLatin1().data(), callbacks, 0, &con); if(r != SASL_OK) { err = saslErrorCond(r); return false; } if(!setsecprops()) return false; const char *ml; r = sasl_listmech(con, 0, NULL, " ", NULL, &ml, 0, 0); if(r != SASL_OK) return false; *mechlist = QString(ml).split(' ', QString::SkipEmptyParts); servermode = true; step = 0; ca_done = false; ca_skip = false; return true; }
virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitelist) { virNetSASLContextPtr ctxt; int err; if (virNetSASLContextInitialize() < 0) return NULL; err = sasl_server_init(NULL, "libvirt"); if (err != SASL_OK) { virReportError(VIR_ERR_AUTH_FAILED, _("failed to initialize SASL library: %d (%s)"), err, sasl_errstring(err, NULL, NULL)); return NULL; } if (!(ctxt = virObjectLockableNew(virNetSASLContextClass))) return NULL; ctxt->usernameWhitelist = usernameWhitelist; return ctxt; }
DWORD VmDirSASLInit( VOID ) { DWORD dwError = 0; static sasl_callback_t saslServerCB[] = { { SASL_CB_LOG, (int (*)(void))_VmDirSASLLog, NULL }, { SASL_CB_GETPATH, (int (*)(void)) _VmDirSASL2PATH, &g_pszSASL2Path }, { SASL_CB_LIST_END, NULL, NULL } }; dwError = VmDirSASL2PATH(&g_pszSASL2Path); BAIL_ON_VMDIR_ERROR(dwError); // provide SASL mutex functions sasl_set_mutex( _VmDirSASLMutexNew, _VmDirSASLMutexLock, _VmDirSASLMutexUnlock, _VmDirSASLMutexDispose); dwError = sasl_server_init( saslServerCB, "vmdird"); BAIL_ON_SASL_ERROR(dwError); cleanup: return dwError; error: VMDIR_SAFE_FREE_MEMORY(g_pszSASL2Path); sasl_error: goto cleanup; }
int auth_cyrus_sasl_server(auth_instance *ablock, uschar *data) { auth_cyrus_sasl_options_block *ob = (auth_cyrus_sasl_options_block *)(ablock->options_block); uschar *output, *out2, *input, *clear, *hname; uschar *debug = NULL; /* Stops compiler complaining */ sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}}; sasl_conn_t *conn; int rc, firsttime=1, clen; unsigned int inlen, outlen; input=data; inlen=Ustrlen(data); HDEBUG(D_auth) debug=string_copy(data); hname=expand_string(ob->server_hostname); if(hname == NULL) { auth_defer_msg = expand_string_message; return DEFER; } if(inlen) { clen=auth_b64decode(input, &clear); if(clen < 0) { return BAD64; } input=clear; inlen=clen; } rc=sasl_server_init(cbs, "exim"); if (rc != SASL_OK) { auth_defer_msg = US"couldn't initialise Cyrus SASL library"; return DEFER; } rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL, NULL, NULL, 0, &conn); if( rc != SASL_OK ) { auth_defer_msg = US"couldn't initialise Cyrus SASL connection"; sasl_done(); return DEFER; } rc=SASL_CONTINUE; while(rc==SASL_CONTINUE) { if(firsttime) { firsttime=0; HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug); rc=sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen, (const char **)(&output), &outlen); } else { /* make sure that we have a null-terminated string */ out2=store_get(outlen+1); memcpy(out2,output,outlen); out2[outlen]='\0'; if((rc=auth_get_data(&input, out2, outlen))!=OK) { /* we couldn't get the data, so free up the library before * returning whatever error we get */ sasl_dispose(&conn); sasl_done(); return rc; } inlen=Ustrlen(input); HDEBUG(D_auth) debug=string_copy(input); if(inlen) { clen=auth_b64decode(input, &clear); if(clen < 0) { sasl_dispose(&conn); sasl_done(); return BAD64; } input=clear; inlen=clen; } HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug); rc=sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen); } if(rc==SASL_BADPROT) { sasl_dispose(&conn); sasl_done(); return UNEXPECTED; } else if( rc==SASL_FAIL || rc==SASL_BUFOVER || rc==SASL_BADMAC || rc==SASL_BADAUTH || rc==SASL_NOAUTHZ || rc==SASL_ENCRYPT || rc==SASL_EXPIRED || rc==SASL_DISABLED || rc==SASL_NOUSER ) { /* these are considered permanent failure codes */ HDEBUG(D_auth) debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return FAIL; } else if(rc==SASL_NOMECH) { /* this is a temporary failure, because the mechanism is not * available for this user. If it wasn't available at all, we * shouldn't have got here in the first place... */ HDEBUG(D_auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech); sasl_dispose(&conn); sasl_done(); return DEFER; } else if(!(rc==SASL_OK || rc==SASL_CONTINUE)) { /* Anything else is a temporary failure, and we'll let SASL print out * the error string for us */ HDEBUG(D_auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return DEFER; } else if(rc==SASL_OK) { /* Get the username and copy it into $auth1 and $1. The former is now the preferred variable; the latter is the original variable. */ rc = sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2)); auth_vars[0] = expand_nstring[1] = string_copy(out2); expand_nlength[1] = Ustrlen(expand_nstring[1]); expand_nmax = 1; HDEBUG(D_auth) debug_printf("Cyrus SASL %s authentication succeeded for %s\n", ob->server_mech, out2); /* close down the connection, freeing up library's memory */ sasl_dispose(&conn); sasl_done(); /* Expand server_condition as an authorization check */ return auth_check_serv_cond(ablock); } } /* NOTREACHED */ return 0; /* Stop compiler complaints */ }
int main(int argc, char *argv[]) { char line[8192]; char *username, *password; #if SASL_VERSION_MAJOR < 2 const char *errstr; #endif int rc; sasl_conn_t *conn = NULL; /* make standard output line buffered */ setvbuf(stdout, NULL, _IOLBF, 0); rc = sasl_server_init( NULL, APP_NAME_SASL ); if ( rc != SASL_OK ) { fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL )); fprintf( stdout, "ERR\n" ); return 1; } #if SASL_VERSION_MAJOR < 2 rc = sasl_server_new( APP_NAME_SASL, NULL, NULL, NULL, 0, &conn ); #else rc = sasl_server_new( APP_NAME_SASL, NULL, NULL, NULL, NULL, NULL, 0, &conn ); #endif if ( rc != SASL_OK ) { fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL )); fprintf( stdout, "ERR\n" ); return 1; } while ( fgets( line, sizeof( line ), stdin )) { username = &line[0]; password = strchr( line, '\n' ); if ( !password) { fprintf( stderr, "authenticator: Unexpected input '%s'\n", line ); fprintf( stdout, "ERR\n" ); continue; } *password = '******'; password = strchr ( line, ' ' ); if ( !password) { fprintf( stderr, "authenticator: Unexpected input '%s'\n", line ); fprintf( stdout, "ERR\n" ); continue; } *password++ = '\0'; rfc1738_unescape(username); rfc1738_unescape(password); #if SASL_VERSION_MAJOR < 2 rc = sasl_checkpass(conn, username, strlen(username), password, strlen(password), &errstr); #else rc = sasl_checkpass(conn, username, strlen(username), password, strlen(password)); #endif if ( rc != SASL_OK ) { #if SASL_VERSION_MAJOR < 2 if ( errstr ) { fprintf( stderr, "errstr %s\n", errstr ); } if ( rc != SASL_BADAUTH ) { fprintf( stderr, "error %d %s\n", rc, sasl_errstring(rc, NULL, NULL )); } #endif fprintf( stdout, "ERR\n" ); } else { fprintf( stdout, "OK\n" ); } } sasl_dispose( &conn ); sasl_done(); return 0; }
int main(int argc, char *argv[]) { int c; char *port = "12345"; char *service = "rcmd"; char *hostname = NULL; int *l, maxfd=0; int r, i; sasl_conn_t *conn; int cb_flag = 0; while ((c = getopt(argc, argv, "Cch:p:s:m:")) != EOF) { switch(c) { case 'C': cb_flag = 2; /* channel bindings are critical */ break; case 'c': cb_flag = 1; /* channel bindings are present */ break; case 'h': hostname = optarg; break; case 'p': port = optarg; break; case 's': service = optarg; break; case 'm': mech = optarg; break; default: usage(); break; } } /* initialize the sasl library */ r = sasl_server_init(NULL, "sample"); if (r != SASL_OK) saslfail(r, "initializing libsasl"); /* get a listening socket */ if ((l = listensock(port, PF_UNSPEC)) == NULL) { saslfail(SASL_FAIL, "allocating listensock"); } for (i = 1; i <= l[0]; i++) { if (l[i] > maxfd) maxfd = l[i]; } for (;;) { char localaddr[NI_MAXHOST | NI_MAXSERV], remoteaddr[NI_MAXHOST | NI_MAXSERV]; char myhostname[1024+1]; char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; struct sockaddr_storage local_ip, remote_ip; int niflags, error; socklen_t salen; int nfds, fd = -1; FILE *in, *out; fd_set readfds; sasl_channel_binding_t cb; FD_ZERO(&readfds); for (i = 1; i <= l[0]; i++) FD_SET(l[i], &readfds); nfds = select(maxfd + 1, &readfds, 0, 0, 0); if (nfds <= 0) { if (nfds < 0 && errno != EINTR) perror("select"); continue; } for (i = 1; i <= l[0]; i++) if (FD_ISSET(l[i], &readfds)) { fd = accept(l[i], NULL, NULL); break; } if (fd < 0) { if (errno != EINTR) perror("accept"); continue; } printf("accepted new connection\n"); /* set ip addresses */ salen = sizeof(local_ip); if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) { perror("getsockname"); } niflags = (NI_NUMERICHOST | NI_NUMERICSERV); #ifdef NI_WITHSCOPEID if (((struct sockaddr *)&local_ip)->sa_family == AF_INET6) niflags |= NI_WITHSCOPEID; #endif error = getnameinfo((struct sockaddr *)&local_ip, salen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), niflags); if (error != 0) { fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error)); strcpy(hbuf, "unknown"); strcpy(pbuf, "unknown"); } snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf); salen = sizeof(remote_ip); if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) { perror("getpeername"); } niflags = (NI_NUMERICHOST | NI_NUMERICSERV); #ifdef NI_WITHSCOPEID if (((struct sockaddr *)&remote_ip)->sa_family == AF_INET6) niflags |= NI_WITHSCOPEID; #endif error = getnameinfo((struct sockaddr *)&remote_ip, salen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), niflags); if (error != 0) { fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error)); strcpy(hbuf, "unknown"); strcpy(pbuf, "unknown"); } snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf); if (hostname == NULL) { r = gethostname(myhostname, sizeof(myhostname)-1); if(r == -1) saslfail(r, "getting hostname"); hostname = myhostname; } r = sasl_server_new(service, hostname, NULL, localaddr, remoteaddr, NULL, 0, &conn); if (r != SASL_OK) saslfail(r, "allocating connection state"); cb.name = "sasl-sample"; cb.critical = cb_flag > 1; cb.data = "this is a test of channel binding"; cb.len = strlen(cb.data); if (cb_flag) { sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb); } /* set external properties here sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */ /* set required security properties here sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */ in = fdopen(fd, "r"); out = fdopen(fd, "w"); r = mysasl_negotiate(in, out, conn); if (r == SASL_OK) { /* send/receive data */ } printf("closing connection\n"); fclose(in); fclose(out); close(fd); sasl_dispose(&conn); } sasl_done(); }
int main(int argc, char **argv) { const char *user, *realm, *passwd, *service, *mechs, **globals, *err; int c, ret; sasl_callback_t callbacks[] = { {SASL_CB_GETOPT, my_getopt, NULL}, {SASL_CB_LIST_END}, }; sasl_conn_t *connection; char hostname[512]; char fulluser[512]; /* XXX: may overflow */ user = realm = passwd = service = ""; strcpy(hostname, "localhost"); gethostname(hostname, sizeof(hostname)); while ((c = getopt(argc, argv, "u:r:p:s:h:12v")) != -1) { switch (c) { case 'u': user = optarg; break; case 'r': realm = optarg; break; case 'p': passwd = optarg; break; case 's': service = optarg; break; case 'h': strncpy(hostname, optarg, sizeof(hostname) - 1); hostname[sizeof(hostname) - 1] = '\0'; break; case '1': main_requested_sasl_version = 1; break; case '2': main_requested_sasl_version = 2; break; case 'v': main_verbose++; break; default: printf("Usage: %s [-v] [-1] [-2] " "[-h hostname] " "[-u user] " "[-r realm] " "[-p password] " "[-s service] " "\n", argv[0]); return 2; break; } } if ((strlen(user) == 0) || (strlen(passwd) == 0)) { printf("Usage: %s [-v] [-1] [-2] " "[-h hostname] " "[-u user] " "[-r realm] " "[-p password] " "[-s service] " "\n", argv[0]); return 2; } if (realm && (strlen(realm) > 0)) { sprintf(fulluser, "%s@%s", user, realm); } else { sprintf(fulluser, "%s", user); } ret = sasl_server_init(callbacks, strlen(service) ? service : "sasl-checkpass"); if (ret != SASL_OK) { fprintf(stderr, "Error in sasl_server_init(): %s\n", sasl_errstring(ret, NULL, NULL)); } connection = NULL; ret = sasl_server_new(strlen(service) ? service : "sasl-checkpass", hostname, NULL, #ifdef SASL2 NULL, NULL, #endif callbacks, 0, &connection); if (ret != SASL_OK) { fprintf(stderr, "Error in sasl_server_new(): %s\n", sasl_errstring(ret, NULL, NULL)); } err = NULL; ret = sasl_checkpass(connection, fulluser, strlen(fulluser), passwd, strlen(passwd) #ifndef SASL2 , &err #endif ); switch (ret) { case SASL_OK: printf("OK\n"); break; default: printf("NO: %d", ret); switch (ret) { case SASL_FAIL: err = "generic failure"; break; case SASL_BADAUTH: err = "authentication failure"; break; default: err = NULL; break; } if (err) { printf(" (%s)", err); } printf("\n"); break; } return ret; }
void auth_cyrus_sasl_init(auth_instance *ablock) { auth_cyrus_sasl_options_block *ob = (auth_cyrus_sasl_options_block *)(ablock->options_block); const uschar *list, *listptr, *buffer; int rc, i; unsigned int len; uschar *rs_point, *expanded_hostname; char *realm_expanded; sasl_conn_t *conn; sasl_callback_t cbs[] = { {SASL_CB_GETOPT, NULL, NULL }, {SASL_CB_LIST_END, NULL, NULL}}; /* default the mechanism to our "public name" */ if (ob->server_mech == NULL) ob->server_mech = string_copy(ablock->public_name); expanded_hostname = expand_string(ob->server_hostname); if (expanded_hostname == NULL) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "couldn't expand server_hostname [%s]: %s", ablock->name, ob->server_hostname, expand_string_message); realm_expanded = NULL; if (ob->server_realm != NULL) { realm_expanded = CS expand_string(ob->server_realm); if (realm_expanded == NULL) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "couldn't expand server_realm [%s]: %s", ablock->name, ob->server_realm, expand_string_message); } /* we're going to initialise the library to check that there is an * authenticator of type whatever mechanism we're using */ cbs[0].proc = (int(*)(void)) &mysasl_config; cbs[0].context = ob->server_mech; if ((rc = sasl_server_init(cbs, "exim")) != SASL_OK ) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "couldn't initialise Cyrus SASL library.", ablock->name); if ((rc = sasl_server_new(CS ob->server_service, CS expanded_hostname, realm_expanded, NULL, NULL, NULL, 0, &conn)) != SASL_OK ) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "couldn't initialise Cyrus SASL server connection.", ablock->name); if ((rc = sasl_listmech(conn, NULL, "", ":", "", (const char **)&list, &len, &i)) != SASL_OK ) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "couldn't get Cyrus SASL mechanism list.", ablock->name); i = ':'; listptr = list; HDEBUG(D_auth) { debug_printf("Initialised Cyrus SASL service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n", ob->server_service, expanded_hostname, realm_expanded); debug_printf("Cyrus SASL knows mechanisms: %s\n", list); } /* the store_get / store_reset mechanism is hierarchical * the hierarchy is stored for us behind our back. This point * creates a hierarchy point for this function. */ rs_point = store_get(0); /* loop until either we get to the end of the list, or we match the * public name of this authenticator */ while ( ( buffer = string_nextinlist(&listptr, &i, NULL, 0) ) && strcmpic(buffer,ob->server_mech) ); if (!buffer) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "Cyrus SASL doesn't know about mechanism %s.", ablock->name, ob->server_mech); store_reset(rs_point); HDEBUG(D_auth) debug_printf("Cyrus SASL driver %s: %s initialised\n", ablock->name, ablock->public_name); /* make sure that if we get here then we're allowed to advertise. */ ablock->server = TRUE; sasl_dispose(&conn); sasl_done(); }
int main(int argc, char **argv) { int debug = 0, conftest = 0, nodaemon = 0; int i = 0; unsigned int clilen; struct sockaddr_in cliaddr; struct timeval start, end; char *cnfg = DEF_CNFG; char localhost[MAXNAMLEN + 1], path[MAXNAMLEN + 1]; FILE *pidfp; octet_t oct; ruleset_t *rs; /* * Who am I running as ? */ uname(&myname); /* * spocp_err = 0 ; */ memset(&srv, 0, sizeof(srv_t)); pthread_mutex_init(&(srv.mutex), NULL); pthread_mutex_init(&(srv.mlock), NULL); gethostname(localhost, MAXNAMLEN); #ifdef HAVE_GETDOMAINNAME getdomainname(path, MAXNAMLEN); #else { char *pos; if(pos = strstr(localhost, ".")) strncpy(path, pos+1, MAXNAMLEN); else strcpy(path, ""); } #endif if (0) printf("Domain: %s\n", path); srv.hostname = Strdup(localhost); /* * truncating input strings to reasonable length */ for (i = 0; i < argc; i++) if (strlen(argv[i]) > 512) argv[i][512] = '\0'; while ((i = getopt(argc, argv, "Dhrtf:d:")) != EOF) { switch (i) { case 'D': nodaemon = 1; break; case 'f': cnfg = Strdup(optarg); break; case 'd': debug = atoi(optarg); if (debug < 0) debug = 0; break; case 't': conftest = 1; break; case 'r': srv.readonly = 1; case 'h': default: fprintf(stderr, "Usage: %s [-t] ", argv[0]); fprintf(stderr, "[-f configfile] "); fprintf(stderr, "[-D] [-d debuglevel]\n"); exit(0); } } srv.root = ruleset_new(0); if (srv_init(&srv, cnfg) < 0) exit(1); if (srv.port && srv.uds) { fprintf(stderr, "Sorry are not allowed to listen on both a unix domain socket and a port\n"); exit(1); } if (srv.logfile) spocp_open_log(srv.logfile, debug); else if (debug) spocp_open_log(0, debug); if (srv.name){ localcontext = (char *) Calloc(strlen(srv.name) + strlen("//") + 1, sizeof(char)); /* Flawfinder: ignore */ sprintf(localcontext, "//%s", srv.name); } else { localcontext = (char *) Calloc(strlen(localhost) + strlen("//") + 1, sizeof(char)); /* Flawfinder: ignore */ sprintf(localcontext, "//%s", localhost); } /* * where I put the access rules for access to this server and its * rules */ snprintf(path, MAXNAMLEN, "%s/server", localcontext); oct_assign(&oct, path); if ((rs = ruleset_create(&oct, srv.root)) == 0) exit(1); rs->db = db_new(); /* * access rules for operations */ snprintf(path, MAXNAMLEN, "%s/operation", localcontext); oct_assign(&oct, path); if ((rs = ruleset_create(&oct, srv.root)) == 0) exit(1); rs->db = db_new(); LOG(SPOCP_INFO) { traceLog(LOG_INFO, "Local context: \"%s\"", localcontext); traceLog(LOG_INFO, "initializing backends"); if (srv.root->db) plugin_display(srv.plugin); } if (srv.plugin) { run_plugin_init(&srv); } if ( get_rules( &srv ) != SPOCP_SUCCESS ) exit(1); /*ruleset_tree( srv.root, 0);*/ /* If only testing configuration and rulefile this is as far as I go */ if (conftest) { traceLog(LOG_INFO,"Configuration was OK"); exit(0); } gettimeofday(&start, NULL); if (srv.port || srv.uds) { /* * stdin and stdout will not be used from here on, close to * save file descriptors */ fclose(stdin); fclose(stdout); #ifdef HAVE_SSL /* * ---------------------------------------------------------- */ /* * build our SSL context, whether it will ever be used or not */ /* * mutex'es for openSSL to use */ THREAD_setup(); if (srv.certificateFile && srv.privateKey && srv.caList) { traceLog(LOG_INFO,"Initializing the TLS/SSL environment"); if (!(srv.ctx = tls_init(&srv))) { return FALSE; } } /* * ---------------------------------------------------------- */ #endif #ifdef HAVE_SASL { int r = sasl_server_init(sasl_cb, "spocp"); if (r != SASL_OK) { traceLog( LOG_ERR, "Unable to initialized SASL library: %s", sasl_errstring(r, NULL, NULL)); return FALSE; } } #endif saci_init(); if( nodaemon == 0 ) { #ifdef HAVE_DAEMON if (daemon(1, 1) < 0) { fprintf(stderr, "couldn't go daemon\n"); exit(1); } #else daemon_init("spocp", 0); #endif } if (srv.pidfile) { /* * Write the PID file. */ pidfp = fopen(srv.pidfile, "w"); if (pidfp == (FILE *) 0) { fprintf(stderr, "Couldn't open pidfile \"%s\"\n", srv.pidfile); exit(1); } fprintf(pidfp, "%d\n", (int) getpid()); fclose(pidfp); } if (srv.port) { LOG(SPOCP_INFO) traceLog( LOG_INFO, "Asked to listen on port %d", srv.port); if ((srv.listen_fd = spocp_stream_socket(srv.port)) < 0) exit(1); srv.id = (char *) Malloc(16); sprintf(srv.id, "spocp-%d", srv.port); srv.type = AF_INET; } else { LOG(SPOCP_INFO) traceLog(LOG_INFO,"Asked to listen on unix domain socket"); if ((srv.listen_fd = spocp_unix_domain_socket(srv.uds)) < 0) exit(1); srv.id = (char *) Malloc(7 + strlen(srv.uds)); /* Flawfinder: ignore */ sprintf(srv.id, "spocp-%s", srv.uds); srv.type = AF_UNIX; } xsignal(SIGCHLD, sig_chld); xsignal(SIGPIPE, sig_pipe); xsignal(SIGINT, sig_int); xsignal(SIGTERM, sig_term); xsignal(SIGUSR1, sig_usr1); clilen = sizeof(cliaddr); DEBUG(SPOCP_DSRV) traceLog(LOG_DEBUG,"Creating threads"); /* * returns the pool the threads are picking work from */ srv.work = tpool_init(srv.threads, 64, 1); spocp_srv_run(&srv); } else { conn_t *conn; saci_init(); DEBUG(SPOCP_DSRV) traceLog(LOG_DEBUG,"---->"); LOG(SPOCP_INFO) traceLog(LOG_INFO,"Reading STDIN"); /* * If I want to use this I have to do init_server() first * conn = spocp_open_connection( STDIN_FILENO, &srv ) ; */ /* * this is much simpler */ conn = conn_new(); conn_setup(conn, &srv, STDIN_FILENO, "localhost", "127.0.0.1"); LOG(SPOCP_INFO) traceLog(LOG_INFO,"Running server"); spocp_server((void *) conn); gettimeofday(&end, NULL); print_elapsed("query time:", start, end); conn_free( conn ); } srv_free( &srv ); if (cnfg != DEF_CNFG) Free( cnfg ); exit(0); }
int auth_cyrus_sasl_server(auth_instance *ablock, uschar *data) { auth_cyrus_sasl_options_block *ob = (auth_cyrus_sasl_options_block *)(ablock->options_block); uschar *output, *out2, *input, *clear, *hname; uschar *debug = NULL; /* Stops compiler complaining */ sasl_callback_t cbs[] = {{SASL_CB_LIST_END, NULL, NULL}}; sasl_conn_t *conn; char * realm_expanded = NULL; int rc, firsttime = 1, clen, *negotiated_ssf_ptr = NULL, negotiated_ssf; unsigned int inlen, outlen; input = data; inlen = Ustrlen(data); HDEBUG(D_auth) debug = string_copy(data); hname = expand_string(ob->server_hostname); if (hname && ob->server_realm) realm_expanded = CS expand_string(ob->server_realm); if (!hname || !realm_expanded && ob->server_realm) { auth_defer_msg = expand_string_message; return DEFER; } if (inlen) { if ((clen = b64decode(input, &clear)) < 0) return BAD64; input = clear; inlen = clen; } if ((rc = sasl_server_init(cbs, "exim")) != SASL_OK) { auth_defer_msg = US"couldn't initialise Cyrus SASL library"; return DEFER; } rc = sasl_server_new(CS ob->server_service, CS hname, realm_expanded, NULL, NULL, NULL, 0, &conn); HDEBUG(D_auth) debug_printf("Initialised Cyrus SASL server connection; service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n", ob->server_service, hname, realm_expanded); if (rc != SASL_OK ) { auth_defer_msg = US"couldn't initialise Cyrus SASL connection"; sasl_done(); return DEFER; } if (tls_in.cipher) { if ((rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, (sasl_ssf_t *) &tls_in.bits)) != SASL_OK) { HDEBUG(D_auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n", tls_in.bits, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = US"couldn't set Cyrus SASL EXTERNAL SSF"; sasl_done(); return DEFER; } else HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_in.bits); } else HDEBUG(D_auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n"); /* So sasl_setprop() documents non-shorted IPv6 addresses which is incredibly annoying; looking at cyrus-imapd-2.3.x source, the IP address is constructed with their iptostring() function, which just wraps getnameinfo(..., NI_NUMERICHOST|NI_NUMERICSERV), which is equivalent to the inet_ntop which we wrap in our host_ntoa() function. So the docs are too strict and we shouldn't worry about :: contractions. */ /* Set properties for remote and local host-ip;port */ for (int i = 0; i < 2; ++i) { struct sockaddr_storage ss; int (*query)(int, struct sockaddr *, socklen_t *); int propnum, port; const uschar *label; uschar *address, *address_port; const char *s_err; socklen_t sslen; if (i) { query = &getpeername; propnum = SASL_IPREMOTEPORT; label = CUS"peer"; } else { query = &getsockname; propnum = SASL_IPLOCALPORT; label = CUS"local"; } sslen = sizeof(ss); if ((rc = query(fileno(smtp_in), (struct sockaddr *) &ss, &sslen)) < 0) { HDEBUG(D_auth) debug_printf("Failed to get %s address information: %s\n", label, strerror(errno)); break; } address = host_ntoa(-1, &ss, NULL, &port); address_port = string_sprintf("%s;%d", address, port); if ((rc = sasl_setprop(conn, propnum, address_port)) != SASL_OK) { s_err = sasl_errdetail(conn); HDEBUG(D_auth) debug_printf("Failed to set %s SASL property: [%d] %s\n", label, rc, s_err ? s_err : "<unknown reason>"); break; } HDEBUG(D_auth) debug_printf("Cyrus SASL set %s hostport to: %s\n", label, address_port); } for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) { if (firsttime) { firsttime = 0; HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug); rc = sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen, (const char **)(&output), &outlen); } else { /* make sure that we have a null-terminated string */ out2 = string_copyn(output, outlen); if ((rc = auth_get_data(&input, out2, outlen)) != OK) { /* we couldn't get the data, so free up the library before * returning whatever error we get */ sasl_dispose(&conn); sasl_done(); return rc; } inlen = Ustrlen(input); HDEBUG(D_auth) debug = string_copy(input); if (inlen) { if ((clen = b64decode(input, &clear)) < 0) { sasl_dispose(&conn); sasl_done(); return BAD64; } input = clear; inlen = clen; } HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug); rc = sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen); } if (rc == SASL_BADPROT) { sasl_dispose(&conn); sasl_done(); return UNEXPECTED; } if (rc == SASL_CONTINUE) continue; /* Get the username and copy it into $auth1 and $1. The former is now the preferred variable; the latter is the original variable. */ if ((sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2))) != SASL_OK) { HDEBUG(D_auth) debug_printf("Cyrus SASL library will not tell us the username: %s\n", sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL username fetch problem: %s", ablock->name, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return FAIL; } auth_vars[0] = expand_nstring[1] = string_copy(out2); expand_nlength[1] = Ustrlen(out2); expand_nmax = 1; switch (rc) { case SASL_FAIL: case SASL_BUFOVER: case SASL_BADMAC: case SASL_BADAUTH: case SASL_NOAUTHZ: case SASL_ENCRYPT: case SASL_EXPIRED: case SASL_DISABLED: case SASL_NOUSER: /* these are considered permanent failure codes */ HDEBUG(D_auth) debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return FAIL; case SASL_NOMECH: /* this is a temporary failure, because the mechanism is not * available for this user. If it wasn't available at all, we * shouldn't have got here in the first place... */ HDEBUG(D_auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech); sasl_dispose(&conn); sasl_done(); return DEFER; case SASL_OK: HDEBUG(D_auth) debug_printf("Cyrus SASL %s authentication succeeded for %s\n", ob->server_mech, auth_vars[0]); if ((rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf_ptr)))!= SASL_OK) { HDEBUG(D_auth) debug_printf("Cyrus SASL library will not tell us the SSF: %s\n", sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL SSF value not available: %s", ablock->name, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return FAIL; } negotiated_ssf = *negotiated_ssf_ptr; HDEBUG(D_auth) debug_printf("Cyrus SASL %s negotiated SSF: %d\n", ob->server_mech, negotiated_ssf); if (negotiated_ssf > 0) { HDEBUG(D_auth) debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL SSF %d not supported by Exim", ablock->name, ob->server_mech, negotiated_ssf); sasl_dispose(&conn); sasl_done(); return FAIL; } /* close down the connection, freeing up library's memory */ sasl_dispose(&conn); sasl_done(); /* Expand server_condition as an authorization check */ return auth_check_serv_cond(ablock); default: /* Anything else is a temporary failure, and we'll let SASL print out * the error string for us */ HDEBUG(D_auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return DEFER; } } /* NOTREACHED */ return 0; /* Stop compiler complaints */ }
XSASL_SERVER_IMPL *xsasl_cyrus_server_init(const char *unused_server_type, const char *path_info) { const char *myname = "xsasl_cyrus_server_init"; XSASL_SERVER_IMPL *xp; int sasl_status; #if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \ || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19)) int sasl_major; int sasl_minor; int sasl_step; /* * DLL hell guard. */ sasl_version_info((const char **) 0, (const char **) 0, &sasl_major, &sasl_minor, &sasl_step, (int *) 0); if (sasl_major != SASL_VERSION_MAJOR #if 0 || sasl_minor != SASL_VERSION_MINOR || sasl_step != SASL_VERSION_STEP #endif ) { msg_warn("incorrect SASL library version. " "Postfix was built with include files from version %d.%d.%d, " "but the run-time library version is %d.%d.%d", SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP, sasl_major, sasl_minor, sasl_step); return (0); } #endif if (*var_cyrus_conf_path) { #ifdef SASL_PATH_TYPE_CONFIG /* Cyrus SASL 2.1.22 */ if (sasl_set_path(SASL_PATH_TYPE_CONFIG, var_cyrus_conf_path) != SASL_OK) msg_warn("failed to set Cyrus SASL configuration path: \"%s\"", var_cyrus_conf_path); #else msg_warn("%s is not empty, but setting the Cyrus SASL configuration " "path is not supported with SASL library version %d.%d.%d", VAR_CYRUS_CONF_PATH, SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP); #endif } /* * Initialize the library: load SASL plug-in routines, etc. */ if (msg_verbose) msg_info("%s: SASL config file is %s.conf", myname, path_info); if ((sasl_status = sasl_server_init(callbacks, path_info)) != SASL_OK) { msg_warn("SASL per-process initialization failed: %s", xsasl_cyrus_strerror(sasl_status)); return (0); } /* * Return a generic XSASL_SERVER_IMPL object. We don't need to extend it * with our own methods or data. */ xp = (XSASL_SERVER_IMPL *) mymalloc(sizeof(*xp)); xp->create = xsasl_cyrus_server_create; xp->done = xsasl_cyrus_server_done; return (xp); }