ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
basic_auth.c
Go to the documentation of this file.
4
6#include <sodium.h>
7#include <string.h>
8
10 if (credentials)
11 sodium_memzero(credentials, sizeof(*credentials));
12}
13
15 if (!authorization || !out)
16 return SET_ERRNO(ERROR_INVALID_PARAM, "Basic authorization arguments are required");
17
18 memset(out, 0, sizeof(*out));
19 while (*authorization == ' ' || *authorization == '\t')
20 ++authorization;
21
22 static const char scheme[] = "Basic";
23 if (platform_strncasecmp(authorization, scheme, sizeof(scheme) - 1) != 0 ||
24 (authorization[sizeof(scheme) - 1] != ' ' && authorization[sizeof(scheme) - 1] != '\t'))
25 return SET_ERRNO(ERROR_INVALID_PARAM, "Authorization is not Basic authentication");
26
27 const char *encoded = authorization + sizeof(scheme) - 1;
28 while (*encoded == ' ' || *encoded == '\t')
29 ++encoded;
30 size_t encoded_length = strlen(encoded);
31 if (!encoded_length || encoded_length > sizeof(*out) * 4 || encoded_length % 4 != 0)
32 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid Basic authorization value");
33
34 uint8_t decoded[sizeof(*out) + 1];
35 size_t decoded_length = 0;
36 if (sodium_base642bin(decoded, sizeof(decoded) - 1, encoded, encoded_length, NULL, &decoded_length, NULL,
37 sodium_base64_VARIANT_ORIGINAL) != 0 ||
38 decoded_length == 0) {
39 sodium_memzero(decoded, sizeof(decoded));
40 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid Basic authorization encoding");
41 }
42 for (size_t i = 0; i < decoded_length; ++i) {
43 if (decoded[i] == '\0') {
44 sodium_memzero(decoded, sizeof(decoded));
45 return SET_ERRNO(ERROR_INVALID_PARAM, "Basic authorization contains an embedded NUL");
46 }
47 }
48
49 char *separator = memchr(decoded, ':', decoded_length);
50 if (!separator || separator == (char *)decoded || (size_t)(separator - (char *)decoded) >= sizeof(out->username) ||
51 decoded_length - (size_t)(separator - (char *)decoded) - 1 == 0 ||
52 decoded_length - (size_t)(separator - (char *)decoded) - 1 >= sizeof(out->password)) {
53 sodium_memzero(decoded, sizeof(decoded));
54 return SET_ERRNO(ERROR_INVALID_PARAM, "Basic authorization must contain username and password");
55 }
56 size_t username_length = (size_t)(separator - (char *)decoded);
57 size_t password_length = decoded_length - username_length - 1;
58 memcpy(out->username, decoded, username_length);
59 memcpy(out->password, separator + 1, password_length);
60 sodium_memzero(decoded, sizeof(decoded));
61 return ASCIICHAT_OK;
62}
63
64bool http_basic_auth_matches(const http_basic_credentials_t *provided, const char *username, const char *password) {
65 if (!provided || !username || !password) {
66 (void)SET_ERRNO(ERROR_INVALID_PARAM, "Basic credential comparison arguments are required");
67 return false;
68 }
69
70 uint8_t expected_username[HTTP_BASIC_AUTH_VALUE_CAPACITY] = {0};
71 uint8_t expected_password[HTTP_BASIC_AUTH_VALUE_CAPACITY] = {0};
72 bool expected_username_terminated = false, expected_password_terminated = false;
73 for (size_t i = 0; i < HTTP_BASIC_AUTH_VALUE_CAPACITY; ++i) {
74 if (!expected_username_terminated) {
75 expected_username[i] = (uint8_t)username[i];
76 if (!username[i])
77 expected_username_terminated = true;
78 }
79 if (!expected_password_terminated) {
80 expected_password[i] = (uint8_t)password[i];
81 if (!password[i])
82 expected_password_terminated = true;
83 }
84 }
85 bool provided_username_terminated = false, provided_password_terminated = false;
86 for (size_t i = 0; i < HTTP_BASIC_AUTH_VALUE_CAPACITY; ++i) {
87 if (!provided_username_terminated && !provided->username[i])
88 provided_username_terminated = true;
89 if (!provided_password_terminated && !provided->password[i])
90 provided_password_terminated = true;
91 }
92 int username_comparison = sodium_memcmp(provided->username, expected_username, HTTP_BASIC_AUTH_VALUE_CAPACITY);
93 int password_comparison = sodium_memcmp(provided->password, expected_password, HTTP_BASIC_AUTH_VALUE_CAPACITY);
94 bool username_match = expected_username_terminated && provided_username_terminated && username_comparison == 0;
95 bool password_match = expected_password_terminated && provided_password_terminated && password_comparison == 0;
96 sodium_memzero(expected_username, sizeof(expected_username));
97 sodium_memzero(expected_password, sizeof(expected_password));
98 return username_match && password_match;
99}
100
101bool http_basic_auth_authorize(const http_basic_auth_config_t *config, const char *authorization) {
102 if (!config) {
103 (void)SET_ERRNO(ERROR_INVALID_PARAM, "Missing Basic authentication configuration");
104 return false;
105 }
106 if (!config->enabled)
107 return true;
108 if (!config->username || !config->password || !config->username[0] || !config->password[0]) {
109 (void)SET_ERRNO(ERROR_INVALID_PARAM, "Basic authentication requires non-empty credentials");
110 return false;
111 }
112 http_basic_credentials_t credentials;
113 bool authorized = authorization && http_basic_auth_parse(authorization, &credentials) == ASCIICHAT_OK &&
114 http_basic_auth_matches(&credentials, config->username, config->password);
115 http_basic_credentials_clear(&credentials);
116 return authorized;
117}
118
119bool http_server_authorize(const http_basic_auth_config_t *config, const struct http_request_info *request,
120 struct http_response *response) {
121 if (!config || !request || !response) {
122 (void)SET_ERRNO(ERROR_INVALID_PARAM, "Basic authorization request arguments are required");
123 return false;
124 }
125 if (!config->enabled)
126 return true;
127 const char *authorization = NULL;
128 for (size_t i = 0; i < request->header_count; ++i) {
129 if (!platform_strcasecmp(request->headers[i].name, "authorization")) {
130 authorization = request->headers[i].value;
131 break;
132 }
133 }
134 if (http_basic_auth_authorize(config, authorization))
135 return true;
137 if (http_response_set_status(response, 401) != ASCIICHAT_OK)
138 return false;
139 const char *realm = config->realm && config->realm[0] ? config->realm : "ascii-chat";
140 char challenge[256];
141 if (safe_snprintf(challenge, sizeof(challenge), "Basic realm=\"%s\"", realm) < 0 ||
142 http_response_set_header(response, "WWW-Authenticate", challenge) != ASCIICHAT_OK)
143 return false;
144 (void)http_response_finish(response);
145 return false;
146}
#define SET_ERRNO(code,...)
void http_basic_credentials_clear(http_basic_credentials_t *credentials)
Definition basic_auth.c:9
bool http_server_authorize(const http_basic_auth_config_t *config, const struct http_request_info *request, struct http_response *response)
Definition basic_auth.c:119
bool http_basic_auth_authorize(const http_basic_auth_config_t *config, const char *authorization)
Definition basic_auth.c:101
bool http_basic_auth_matches(const http_basic_credentials_t *provided, const char *username, const char *password)
Definition basic_auth.c:64
asciichat_error_t http_basic_auth_parse(const char *authorization, http_basic_credentials_t *out)
Definition basic_auth.c:14
struct http_basic_auth_config http_basic_auth_config_t
#define HTTP_BASIC_AUTH_VALUE_CAPACITY
Definition basic_auth.h:9
struct http_basic_credentials http_basic_credentials_t
unsigned char uint8_t
Definition common.h:60
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
Backend-neutral HTTP request/response contract.
asciichat_error_t http_response_set_status(http_response_t *r, unsigned s)
asciichat_error_t http_response_set_header(http_response_t *r, const char *n, const char *v)
asciichat_error_t http_response_finish(http_response_t *r)
void stats_counter_add(stats_scope_t *scope, stats_counter_id_t id, uint64_t amount)
static bool size_t gotel_query_t * out
Definition queries.h:8
stats_scope_t * stats_runtime_scope(void)
Definition runtime.c:80
🔤 String Manipulation and Shell Escaping Utilities
const char * password
Definition basic_auth.h:14
const char * username
Definition basic_auth.h:13