/* Examine a Basic auth challenge. * Returns 0 if an valid challenge, else non-zero. */ static int basic_challenge(http_auth_session *sess, struct http_auth_chall *parms) { char *tmp, *password; /* Verify challenge... must have a realm */ if (parms->realm == NULL) { return -1; } DEBUG(DEBUG_HTTPAUTH, "Got Basic challenge with realm [%s]\n", parms->realm); clean_session(sess); sess->unq_realm = shave_string(parms->realm, '"'); if (get_credentials(sess, &password)) { /* Failed to get credentials */ HTTP_FREE(sess->unq_realm); return -1; } sess->scheme = http_auth_scheme_basic; CONCAT3(tmp, sess->username, ":", password?password:""); sess->basic = base64(tmp); free(tmp); HTTP_FREE(password); return 0; }
static int parse_domain(http_auth_session *sess, const char *domain) { char *unq, **doms; int count, ret; unq = shave_string(domain, '"'); doms = split_string_c(unq, ' ', NULL, HTTP_WHITESPACE, &count); if (doms != NULL) { if (count > 0) { sess->domain = doms; sess->domain_count = count; ret = 0; } else { free(doms); ret = -1; } } else { ret = -1; } free(unq); return ret; }
void ComptaOptions::print_options(const std::string & keyword, const std::string & value) { compta_assert(_print_options_map.count(keyword)); switch(_print_options_map.at(keyword)) { case PRINT::ALL: { std::string lvalue(value); std::transform(lvalue.begin(),lvalue.end(),lvalue.begin(),::tolower); if(lvalue == NO) { _print_forecast = false; _print_bank = false; _print_cash = false; }else if(lvalue == YES) { _print_forecast = true; _print_bank = true; _print_cash = true; }else { compta_option_error("Unrecognized value for option --print: " + value + "\nPlease use \"" + YES + "\" or \"" + NO + "\""); } break; } case PRINT::FORECAST: { _print_forecast = true; break; } case PRINT::BANK: { _print_bank = true; break; } case PRINT::CASH: { _print_cash = true; break; } case PRINT::BANK_HISTORY: { if(SplitString(value,",",_print_bank_history,false) == 0)_print_bank_history.push_back(value); shave_string(_print_bank_history); break; } case PRINT::CASH_HISTORY: { if(SplitString(value,",",_print_cash_history,false) == 0)_print_cash_history.push_back(value); shave_string(_print_cash_history); break; } case PRINT::ALL_DATA: { _print_all_data = true; break; } case PRINT::FROM: { _from_stdout.set_date(value); break; } case PRINT::TO: { _to_stdout.set_date(value); break; } default: //WTF??? { compta_error(); } } }
/* A new challenge presented by the server */ int http_auth_challenge(http_auth_session *sess, const char *value) { char **pairs, *pnt, *unquoted, *key; struct http_auth_chall *chall = NULL, *challenges = NULL; int n, success; DEBUG(DEBUG_HTTPAUTH, "Got new auth challenge: %s\n", value); /* The header value may be made up of one or more challenges. * We split it down into attribute-value pairs, then search for * schemes in the pair keys. */ pairs = pair_string(value, ',', '=', HTTP_QUOTES, HTTP_WHITESPACE); for (n = 0; pairs[n]!=NULL; n+=2) { /* Look for an auth-scheme in the key */ pnt = strchr(pairs[n], ' '); if (pnt != NULL) { /* We have a new challenge */ DEBUG(DEBUG_HTTPAUTH, "New challenge.\n"); chall = ne_calloc(sizeof *chall); chall->next = challenges; challenges = chall; /* Initialize the challenge parameters */ /* Which auth-scheme is it (case-insensitive matching) */ if (strncasecmp(pairs[n], "basic ", 6) == 0) { DEBUG(DEBUG_HTTPAUTH, "Basic scheme.\n"); chall->scheme = http_auth_scheme_basic; } else if (strncasecmp(pairs[n], "digest ", 7) == 0) { DEBUG(DEBUG_HTTPAUTH, "Digest scheme.\n"); chall->scheme = http_auth_scheme_digest; } else { DEBUG(DEBUG_HTTPAUTH, "Unknown scheme.\n"); free(chall); challenges = NULL; break; } /* Now, the real key for this pair starts after the * auth-scheme... skipping whitespace */ while (strchr(HTTP_WHITESPACE, *(++pnt)) != NULL) /* nullop */; key = pnt; } else if (chall == NULL) { /* If we haven't got an auth-scheme, and we're * haven't yet found a challenge, skip this pair. */ continue; } else { key = pairs[n]; } DEBUG(DEBUG_HTTPAUTH, "Got pair: [%s] = [%s]\n", key, pairs[n+1]); /* Most values are quoted, so unquote them here */ unquoted = shave_string(pairs[n+1], '"'); /* Now parse the attribute */ DEBUG(DEBUG_HTTPAUTH, "Unquoted pair is: [%s]\n", unquoted); if (strcasecmp(key, "realm") == 0) { chall->realm = pairs[n+1]; } else if (strcasecmp(key, "nonce") == 0) { chall->nonce = pairs[n+1]; } else if (strcasecmp(key, "opaque") == 0) { chall->opaque = pairs[n+1]; } else if (strcasecmp(key, "domain") == 0) { chall->domain = pairs[n+1]; } else if (strcasecmp(key, "stale") == 0) { /* Truth value */ chall->stale = (strcasecmp(unquoted, "true") == 0); } else if (strcasecmp(key, "algorithm") == 0) { if (strcasecmp(unquoted, "md5") == 0) { chall->alg = http_auth_alg_md5; } else if (strcasecmp(unquoted, "md5-sess") == 0) { chall->alg = http_auth_alg_md5_sess; } else { chall->alg = http_auth_alg_unknown; } } else if (strcasecmp(key, "qop") == 0) { char **qops; int qop; qops = split_string(unquoted, ',', NULL, HTTP_WHITESPACE); chall->got_qop = 1; for (qop = 0; qops[qop] != NULL; qop++) { if (strcasecmp(qops[qop], "auth") == 0) { chall->qop_auth = 1; } else if (strcasecmp(qops[qop], "auth-int") == 0) { chall->qop_auth_int = 1; } } split_string_free(qops); } free(unquoted); } DEBUG(DEBUG_HTTPAUTH, "Finished parsing parameters.\n"); /* Did we find any challenges */ if (challenges == NULL) { pair_string_free(pairs); return -1; } success = 0; DEBUG(DEBUG_HTTPAUTH, "Looking for Digest challenges.\n"); /* Try a digest challenge */ for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == http_auth_scheme_digest) { if (!digest_challenge(sess, chall)) { success = 1; break; } } } if (!success) { DEBUG(DEBUG_HTTPAUTH, "No good Digest challenges, looking for Basic.\n"); for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == http_auth_scheme_basic) { if (!basic_challenge(sess, chall)) { success = 1; break; } } } if (!success) { /* No good challenges - record this in the session state */ DEBUG(DEBUG_HTTPAUTH, "Did not understand any challenges.\n"); } } /* Remember whether we can now supply the auth details */ sess->can_handle = success; while (challenges != NULL) { chall = challenges->next; free(challenges); challenges = chall; } /* Free up the parsed header values */ pair_string_free(pairs); return !success; }
/* Pass this the value of the 'Authentication-Info:' header field, if * one is received. * Returns: * 0 if it gives a valid authentication for the server * non-zero otherwise (don't believe the response in this case!). */ int http_auth_verify_response(http_auth_session *sess, const char *value) { char **pairs; http_auth_qop qop = http_auth_qop_none; char *nextnonce = NULL, /* for the nextnonce= value */ *rspauth = NULL, /* for the rspauth= value */ *cnonce = NULL, /* for the cnonce= value */ *nc = NULL, /* for the nc= value */ *unquoted, *qop_value = NULL; int n, nonce_count, okay; if (!sess->will_handle) { /* Ignore it */ return 0; } if (sess->scheme != http_auth_scheme_digest) { DEBUG(DEBUG_HTTPAUTH, "Found Auth-Info header not in response to Digest credentials - dodgy.\n"); return -1; } DEBUG (DEBUG_HTTPAUTH, "Auth-Info header: %s\n", value); pairs = pair_string(value, ',', '=', HTTP_QUOTES, HTTP_WHITESPACE); for (n = 0; pairs[n]!=NULL; n+=2) { unquoted = shave_string(pairs[n+1], '"'); if (strcasecmp(pairs[n], "qop") == 0) { qop_value = ne_strdup(pairs[n+1]); if (strcasecmp(pairs[n+1], "auth-int") == 0) { qop = http_auth_qop_auth_int; } else if (strcasecmp(pairs[n+1], "auth") == 0) { qop = http_auth_qop_auth; } else { qop = http_auth_qop_none; } } else if (strcasecmp(pairs[n], "nextnonce") == 0) { nextnonce = ne_strdup(unquoted); } else if (strcasecmp(pairs[n], "rspauth") == 0) { rspauth = ne_strdup(unquoted); } else if (strcasecmp(pairs[n], "cnonce") == 0) { cnonce = ne_strdup(unquoted); } else if (strcasecmp(pairs[n], "nc") == 0) { nc = ne_strdup(pairs[n]); if (sscanf(pairs[n+1], "%x", &nonce_count) != 1) { DEBUG(DEBUG_HTTPAUTH, "Couldn't scan [%s] for nonce count.\n", pairs[n+1]); } else { DEBUG(DEBUG_HTTPAUTH, "Got nonce_count: %d\n", nonce_count); } } free(unquoted); } pair_string_free(pairs); /* Presume the worst */ okay = -1; if ((qop != http_auth_qop_none) && (qop_value != NULL)) { if ((rspauth == NULL) || (cnonce == NULL) || (nc == NULL)) { DEBUG(DEBUG_HTTPAUTH, "Missing rspauth, cnonce or nc with qop.\n"); } else { /* Have got rspauth, cnonce and nc */ if (strcmp(cnonce, sess->unq_cnonce) != 0) { DEBUG(DEBUG_HTTPAUTH, "Response cnonce doesn't match.\n"); } else if (nonce_count != sess->nonce_count) { DEBUG(DEBUG_HTTPAUTH, "Response nonce count doesn't match.\n"); } else { /* Calculate and check the response-digest value. * joe: IMO the spec is slightly ambiguous as to whether * we use the qop which WE sent, or the qop which THEY * sent... */ struct md5_ctx a2; unsigned char a2_md5[16], rdig_md5[16]; char a2_md5_ascii[33], rdig_md5_ascii[33]; DEBUG(DEBUG_HTTPAUTH, "Calculating response-digest.\n"); /* First off, H(A2) again. */ md5_init_ctx(&a2); md5_process_bytes(":", 1, &a2); md5_process_bytes(sess->uri, strlen(sess->uri), &a2); if (qop == http_auth_qop_auth_int) { unsigned char heb_md5[16]; char heb_md5_ascii[33]; /* Add on ":" H(entity-body) */ md5_finish_ctx(&sess->response_body, heb_md5); md5_to_ascii(heb_md5, heb_md5_ascii); md5_process_bytes(":", 1, &a2); md5_process_bytes(heb_md5_ascii, 32, &a2); DEBUG(DEBUG_HTTPAUTH, "Digested [:%s]\n", heb_md5_ascii); } md5_finish_ctx(&a2, a2_md5); md5_to_ascii(a2_md5, a2_md5_ascii); /* We have the stored digest-so-far of * H(A1) ":" unq(nonce-value) * [ ":" nc-value ":" unq(cnonce-value) ] for qop * in sess->stored_rdig, to save digesting them again. * */ if (qop != http_auth_qop_none) { /* Add in qop-value */ DEBUG(DEBUG_HTTPAUTH, "Digesting qop-value [%s:].\n", qop_value); md5_process_bytes(qop_value, strlen(qop_value), &sess->stored_rdig); md5_process_bytes(":", 1, &sess->stored_rdig); } /* Digest ":" H(A2) */ md5_process_bytes(a2_md5_ascii, 32, &sess->stored_rdig); /* All done */ md5_finish_ctx(&sess->stored_rdig, rdig_md5); md5_to_ascii(rdig_md5, rdig_md5_ascii); DEBUG(DEBUG_HTTPAUTH, "Calculated response-digest of: [%s]\n", rdig_md5_ascii); DEBUG(DEBUG_HTTPAUTH, "Given response-digest of: [%s]\n", rspauth); /* And... do they match? */ okay = (strcasecmp(rdig_md5_ascii, rspauth) == 0)?0:-1; DEBUG(DEBUG_HTTPAUTH, "Matched: %s\n", okay?"nope":"YES!"); } free(rspauth); free(cnonce); free(nc); } free(qop_value); } else { DEBUG(DEBUG_HTTPAUTH, "No qop directive, auth okay.\n"); okay = 0; } /* Check for a nextnonce */ if (nextnonce != NULL) { DEBUG(DEBUG_HTTPAUTH, "Found nextnonce of [%s].\n", nextnonce); if (sess->unq_nonce != NULL) free(sess->unq_nonce); sess->unq_nonce = nextnonce; } return okay; }
/* Examine a digest challenge: return 0 if it is a valid Digest challenge, * else non-zero. */ static int digest_challenge(http_auth_session *sess, struct http_auth_chall *parms) { struct md5_ctx tmp; unsigned char tmp_md5[16]; char *password; /* Do we understand this challenge? */ if (parms->alg == http_auth_alg_unknown) { DEBUG(DEBUG_HTTPAUTH, "Unknown algorithm.\n"); return -1; } if ((parms->alg == http_auth_alg_md5_sess) && !(parms->qop_auth || parms->qop_auth_int)) { DEBUG(DEBUG_HTTPAUTH, "Server did not give qop with MD5-session alg.\n"); return -1; } if ((parms->realm==NULL) || (parms->nonce==NULL)) { DEBUG(DEBUG_HTTPAUTH, "Challenge missing nonce or realm.\n"); return -1; } if (parms->stale) { /* Just a stale response, don't need to get a new username/password */ DEBUG(DEBUG_HTTPAUTH, "Stale digest challenge.\n"); } else { /* Forget the old session details */ DEBUG(DEBUG_HTTPAUTH, "In digest challenge.\n"); clean_session(sess); sess->unq_realm = shave_string(parms->realm, '"'); /* Not a stale response: really need user authentication */ if (get_credentials(sess, &password)) { /* Failed to get credentials */ HTTP_FREE(sess->unq_realm); return -1; } } sess->alg = parms->alg; sess->scheme = http_auth_scheme_digest; sess->unq_nonce = shave_string(parms->nonce, '"'); sess->unq_cnonce = get_cnonce(); if (parms->domain) { if (parse_domain(sess, parms->domain)) { /* TODO: Handle the error? */ } } else { sess->domain = NULL; sess->domain_count = 0; } if (parms->opaque != NULL) { sess->opaque = ne_strdup(parms->opaque); /* don't strip the quotes */ } if (parms->got_qop) { /* What type of qop are we to apply to the message? */ DEBUG(DEBUG_HTTPAUTH, "Got qop directive.\n"); sess->nonce_count = 0; if (parms->qop_auth_int) { sess->qop = http_auth_qop_auth_int; } else { sess->qop = http_auth_qop_auth; } } else { /* No qop at all/ */ sess->qop = http_auth_qop_none; } if (!parms->stale) { /* Calculate H(A1). * tmp = H(unq(username-value) ":" unq(realm-value) ":" passwd) */ DEBUG(DEBUG_HTTPAUTH, "Calculating H(A1).\n"); md5_init_ctx(&tmp); md5_process_bytes(sess->username, strlen(sess->username), &tmp); md5_process_bytes(":", 1, &tmp); md5_process_bytes(sess->unq_realm, strlen(sess->unq_realm), &tmp); md5_process_bytes(":", 1, &tmp); if (password != NULL) md5_process_bytes(password, strlen(password), &tmp); md5_finish_ctx(&tmp, tmp_md5); if (sess->alg == http_auth_alg_md5_sess) { unsigned char a1_md5[16]; struct md5_ctx a1; char tmp_md5_ascii[33]; /* Now we calculate the SESSION H(A1) * A1 = H(...above...) ":" unq(nonce-value) ":" unq(cnonce-value) */ md5_to_ascii(tmp_md5, tmp_md5_ascii); md5_init_ctx(&a1); md5_process_bytes(tmp_md5_ascii, 32, &a1); md5_process_bytes(":", 1, &a1); md5_process_bytes(sess->unq_nonce, strlen(sess->unq_nonce), &a1); md5_process_bytes(":", 1, &a1); md5_process_bytes(sess->unq_cnonce, strlen(sess->unq_cnonce), &a1); md5_finish_ctx(&a1, a1_md5); md5_to_ascii(a1_md5, sess->h_a1); DEBUG(DEBUG_HTTPAUTH, "Session H(A1) is [%s]\n", sess->h_a1); } else { md5_to_ascii(tmp_md5, sess->h_a1); DEBUG(DEBUG_HTTPAUTH, "H(A1) is [%s]\n", sess->h_a1); } HTTP_FREE(password); } DEBUG(DEBUG_HTTPAUTH, "I like this Digest challenge.\n"); return 0; }