// haystack is \0 (space if leading upper) (lowercase string), ends with two \0 // needles are a NULL terminated list of lowercase strings, with a leading space if upper int text_search(char* haystack, char** needles, int exact, int* results) { // information about the needles int n = count_pointers(needles); int uppers[n]; // is this needle uppercase prefix int lengths[n]; // length of this needle char* strings[n]; // actual text of this needle for (int i = 0; i < n; i++) { uppers[i] = needles[i][0] == ' '; strings[i] = uppers[i] ? &needles[i][1] : needles[i]; lengths[i] = strlen(strings[i]); } int index = 0; // Number of \n's I've already seen in haystack int found = 0; // Number I've written to results for (index = 0; ; index++) { int upper = haystack[0] == ' '; if (upper) haystack++; int length = strlen(haystack); if (length == 0) break; char* string = haystack; haystack = &haystack[length+1]; int score = 4; for (int i = 0; i < n; i++) { char* pos = strstr(string, strings[i]); // length, strings[i], lengths[i]); if (pos == NULL) { score = -1; break; } else if (pos == string) { int complete = lengths[i] == length; int cased = uppers[i] == upper; score = min_int(score, (!complete ? 2 : 0) + (!cased ? 1 : 0)); } } if (score >= 0 && (!exact || score == 0)) results[found++] = (score << 24) | index; } qsort(results, found, sizeof(int), compare_int); for (int i = 0; i < found; i++) results[i] = results[i] & 0xffffff; return found; }
void socket_thread_handle(socket_thread_data_t *td) { char *buf; char errbuf[ERRBUFLEN + 1]; apr_size_t bufsize = 1024; apr_size_t readsize = bufsize; char **argv; apr_status_t res; dynalogin_result_t dynalogin_res; apr_pool_t *query_pool; int ntokens; char *selected_mode; dynalogin_userid_t userid; dynalogin_scheme_t scheme; dynalogin_code_t code; char *digest_realm; char *digest_response; char *digest_suffix; if((res=apr_pool_create(&query_pool, td->pool))!=APR_SUCCESS) { syslog(LOG_ERR, "failed to create query pool: %s", apr_strerror(res, errbuf, ERRBUFLEN)); return; } if(send_result(td, 220)!=APR_SUCCESS) { syslog(LOG_ERR, "failed to send greeting"); return; } readsize = bufsize; res = read_line(query_pool, td, &buf, bufsize); while(res == APR_SUCCESS || res == APR_EOF) { if((res=apr_tokenize_to_argv(buf, &argv, query_pool)) !=APR_SUCCESS) { syslog(LOG_ERR, "failed to tokenize query: %s", apr_strerror(res, errbuf, ERRBUFLEN)); return; } ntokens = count_pointers(argv); /* Examine the command sent by the client */ if(ntokens < 1) { syslog(LOG_WARNING, "insufficient tokens in query"); res = send_result(td, 500); } else if(strcasecmp(argv[0], "QUIT")==0) { send_result(td, 221); return; } else if(strcasecmp(argv[0], "UDATA")==0) { /* User sending user ID and response value */ selected_mode=argv[1]; if(ntokens < 1) { /* Command too short */ syslog(LOG_WARNING, "insufficient tokens in query"); res = send_result(td, 500); } else if(strcasecmp(selected_mode, "HOTP") == 0 || strcasecmp(selected_mode, "TOTP") == 0) { userid=argv[2]; scheme = selected_mode[0] == 'H' ? HOTP : TOTP; code=argv[3]; if(ntokens < 4) { /* Command too short */ syslog(LOG_WARNING, "insufficient tokens in query"); res = send_result(td, 500); } else { syslog(LOG_DEBUG, "attempting DYNALOGIN auth for user=%s", userid); dynalogin_res = dynalogin_authenticate(td->dynalogin_session, userid, scheme, code); switch(dynalogin_res) { case DYNALOGIN_SUCCESS: syslog(LOG_DEBUG, "DYNALOGIN success for user=%s", userid); res = send_result(td, 250); break; case DYNALOGIN_DENY: /* User unknown or bad password */ syslog(LOG_DEBUG, "DYNALOGIN denied for user=%s", userid); res = send_result(td, 401); break; case DYNALOGIN_ERROR: /* Error connecting to DB, etc */ syslog(LOG_DEBUG, "DYNALOGIN error for user=%s", userid); res = send_result(td, 500); break; default: syslog(LOG_DEBUG, "DYNALOGIN unexpected result for user=%s", userid); res = send_result(td, 500); } } } else if (strcasecmp(selected_mode, "HOTP-DIGEST") == 0 || strcasecmp(selected_mode, "TOTP-DIGEST") == 0) { /* HOTP Digest mode */ userid = argv[2]; scheme = selected_mode[0] == 'H' ? HOTP : TOTP; digest_realm = argv[3]; digest_response = argv[4]; digest_suffix = argv[5]; if(ntokens < 6) { /* Command too short */ syslog(LOG_WARNING, "insufficient tokens in query"); res = send_result(td, 500); } else { syslog(LOG_DEBUG, "attempting DYNALOGIN digest auth for user=%s", userid); dynalogin_res = dynalogin_authenticate_digest(td->dynalogin_session, userid, scheme, digest_response, digest_realm, digest_suffix); switch(dynalogin_res) { case DYNALOGIN_SUCCESS: syslog(LOG_DEBUG, "DYNALOGIN success for user=%s", userid); res = send_result(td, 250); break; case DYNALOGIN_DENY: /* User unknown or bad password */ syslog(LOG_DEBUG, "DYNALOGIN denied for user=%s", userid); res = send_result(td, 401); break; case DYNALOGIN_ERROR: /* Error connecting to DB, etc */ syslog(LOG_DEBUG, "DYNALOGIN error for user=%s", userid); res = send_result(td, 500); break; default: syslog(LOG_DEBUG, "DYNALOGIN unexpected result for user=%s", userid); res = send_result(td, 500); } } } else { syslog(LOG_WARNING, "unsupported mode requested"); res = send_result(td, 500); } } else { /* Unrecognised command */ res = send_result(td, 500); } if(res != APR_SUCCESS) { syslog(LOG_ERR, "failed to send response: %s", apr_strerror(res, errbuf, ERRBUFLEN)); return; } apr_pool_destroy(query_pool); if((res=apr_pool_create(&query_pool, td->pool))!=APR_SUCCESS) { syslog(LOG_ERR, "failed to create query pool: %s", apr_strerror(res, errbuf, ERRBUFLEN)); return; } res = read_line(query_pool, td, &buf, bufsize); } syslog(LOG_ERR, "failed to read input from socket: %s", apr_strerror(res, errbuf, ERRBUFLEN)); }