stringer_t * org_signet_get(prime_org_signet_t *org, stringer_t *output) { size_t length; int_t written = 0; stringer_t *result = NULL; if (!org || !(length = org_signet_length(org))) { log_pedantic("An invalid org signet was supplied for serialization."); return NULL; } // See if we have a valid output buffer, or if output is NULL, allocate a buffer to hold the output. else if (output && (!st_valid_destination(st_opt_get(output)) || st_avail_get(output) < length)) { log_pedantic("An output string was supplied but it does not represent a buffer capable of holding the output."); return NULL; } else if (!output && !(result = st_alloc(length))) { log_pedantic("Could not allocate a buffer large enough to hold encoded result. { requested = %zu }", length); return NULL; } else if (!output) { output = result; } st_wipe(output); // Calculate the size, by writing out all the fields (minus the header) using a NULL output. length = st_write(NULL, prime_field_write(PRIME_ORG_SIGNET, 1, ED25519_KEY_PUB_LEN, ed25519_public_get(org->signing, MANAGEDBUF(32)), MANAGEDBUF(34)), prime_field_write(PRIME_ORG_SIGNET, 3, SECP256K1_KEY_PUB_LEN, secp256k1_public_get(org->encryption, MANAGEDBUF(33)), MANAGEDBUF(35)), prime_field_write(PRIME_ORG_SIGNET, 4, ED25519_SIGNATURE_LEN, org->signature, MANAGEDBUF(65))); // Then output them again into the actual output buffer, but this time include the header. This is very primitive serialization logic. if ((written = st_write(output, prime_header_org_signet_write(length, MANAGEDBUF(5)), prime_field_write(PRIME_ORG_SIGNET, 1, ED25519_KEY_PUB_LEN, ed25519_public_get(org->signing, MANAGEDBUF(32)), MANAGEDBUF(34)), prime_field_write(PRIME_ORG_SIGNET, 3, SECP256K1_KEY_PUB_LEN, secp256k1_public_get(org->encryption, MANAGEDBUF(33)), MANAGEDBUF(35)), prime_field_write(PRIME_ORG_SIGNET, 4, ED25519_SIGNATURE_LEN, org->signature, MANAGEDBUF(65)))) != (length + 5)) { log_pedantic("The organizational signet didn't serialize to the expected length. { written = %i }", written); st_cleanup(result); return NULL; } return output; }
/** * @brief Accept and verify a password for POP3 authentication. * @note This command is only allowed for sessions which have not yet been authenticated, but which have already supplied a username. * If the username/password combo was validated, the account information is retrieved and checked to see if it is locked. * After successful authentication, this function will prohibit insecure connections for any user configured to use SSL only, * and enforce the existence of only one POP3 session at a time. * Finally, the database Log table for this user's POP3 access is updated, and all the user's messages are retrieved. * @param con the POP3 client connection issuing the command. * @return This function returns no value. */ void pop_pass(connection_t *con) { int_t state; credential_t *cred; stringer_t *password, *username; if (con->pop.session_state != 0) { pop_invalid(con); return; } // The user must come before the PASS command. if (st_empty(con->pop.username)) { con_write_bl(con, "-ERR You must supply a username first.\r\n", 40); return; } // If they didn't pass in a valid password. if (!(password = pop_pass_parse(con))) { con_write_bl(con, "-ERR Invalid PASS command.\r\n", 28); return; } // Hash the password. // First we need to get the regular username from the fully qualified one. if (!(username = credential_username(con->pop.username))) { con_write_bl(con, "-ERR Internal server error. Please try again later.\r\n", 53); st_wipe(password); st_free(password); } st_free(con->pop.username); con->pop.username = username; if (!(cred = credential_alloc_auth(con->pop.username, password))) { con_write_bl(con, "-ERR Internal server error. Please try again later.\r\n", 53); st_wipe(password); st_free(password); return; } st_wipe(password); st_free(password); // Pull the user info out. state = meta_get(con->pop.username, cred->auth.domain, cred->auth.password, cred->auth.key, META_PROT_POP, META_GET_MESSAGES, &(con->pop.user)); // Securely delete this information, as these are the keys to the castle. credential_free(cred); // Not found, or invalid password. if (state == 0) { con_write_bl(con, "-ERR The username and password combination is invalid.\r\n", 56); return; } // Internal error. else if (state < 0 || !con->pop.user) { con_write_bl(con, "-ERR [SYS/TEMP] Internal server error. Please try again later.\r\n", 64); return; } // Locks else if (con->pop.user->lock_status != 0) { // What type of lock is it. if (con->pop.user->lock_status == 1) { con_write_bl(con, "-ERR [SYS/PERM] This account has been administratively locked.\r\n", 64); } else if (con->pop.user->lock_status == 2) { con_write_bl(con, "-ERR [SYS/PERM] This account has been locked for inactivity.\r\n", 62); } else if (con->pop.user->lock_status == 3) { con_write_bl(con, "-ERR [SYS/PERM] This account has been locked on suspicion of abuse.\r\n", 69); } else if (con->pop.user->lock_status == 4) { con_write_bl(con, "-ERR [SYS/PERM] This account has been locked at the request of the user.\r\n", 74); } else { con_write_bl(con, "-ERR [SYS/PERM] This account has been locked.\r\n", 47); } con->pop.user = NULL; meta_remove(con->pop.username, META_PROT_POP); return; } // SSL check. else if ((con->pop.user->flags & META_USER_SSL) == META_USER_SSL && con_secure(con) != 1) { con->pop.user = NULL; meta_remove(con->pop.username, META_PROT_POP); con_write_bl(con, "-ERR [SYS/PERM] This user account is configured to require that all POP sessions be connected over SSL.\r\n", 105); return; } // Single session check. else if (con->pop.user->refs.pop != 1) { con->pop.user = NULL; meta_remove(con->pop.username, META_PROT_POP); con_write_bl(con, "-ERR [IN-USE] This account is being used by another session. Please try again in a few minutes.\r\n", 97); return; } // Debug logging. log_pedantic("User %.*s logged in from %s via POP. {poprefs = %lu, imaprefs = %lu, messages = %lu}", st_length_int(con->pop.username), st_char_get(con->pop.username), st_char_get(con_addr_presentation(con, MANAGEDBUF(256))), con->pop.user->refs.pop, con->pop.user->refs.imap, con->pop.user->messages ? inx_count(con->pop.user->messages) : 0); // Update the log and unlock the session. meta_data_update_log(con->pop.user, META_PROT_POP); meta_user_wlock(con->pop.user); meta_messages_login_update(con->pop.user, META_LOCKED); meta_user_unlock(con->pop.user); // Update session state. con->pop.session_state = 1; // Tell the client everything worked. con_write_bl(con, "+OK Password accepted.\r\n", 24); return; }