Client authentication added.
[xiph/unicode.git] / icecast / src / auth.c
blobdb618a40116f063f20f441181de25da9b7aad6ed
1 /**
2 * Client authentication functions
3 */
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
9 #include <stdlib.h>
10 #include <string.h>
11 #include <errno.h>
12 #include <stdio.h>
14 #include "auth.h"
15 #include "source.h"
16 #include "client.h"
17 #include "cfgfile.h"
18 #include "httpp/httpp.h"
19 #include "md5.h"
21 #include "logging.h"
22 #define CATMODULE "auth"
24 auth_result auth_check_client(source_t *source, client_t *client)
26 auth_t *authenticator = source->authenticator;
28 if(authenticator) {
29 /* This will look something like "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" */
30 char *header = httpp_getvar(client->parser, "authorization");
31 char *userpass, *tmp;
32 char *username, *password;
34 if(header == NULL)
35 return AUTH_FAILED;
37 if(strncmp(header, "Basic ", 6)) {
38 INFO0("Authorization not using Basic");
39 return 0;
42 userpass = util_base64_decode(header+6);
43 if(userpass == NULL) {
44 WARN1("Base64 decode of Authorization header \"%s\" failed",
45 header+6);
46 return AUTH_FAILED;
49 tmp = strchr(userpass, ':');
50 if(!tmp) {
51 free(userpass);
52 return AUTH_FAILED;
55 *tmp = 0;
56 username = userpass;
57 password = tmp+1;
59 auth_result result = authenticator->authenticate(
60 authenticator, username, password);
62 if(result == AUTH_OK)
63 client->username = strdup(username);
65 free(userpass);
67 return result;
69 else
70 return AUTH_FAILED;
73 static auth_t *auth_get_htpasswd_auth(config_options_t *options);
75 auth_t *auth_get_authenticator(char *type, config_options_t *options)
77 auth_t *auth = NULL;
78 if(!strcmp(type, "htpasswd")) {
79 auth = auth_get_htpasswd_auth(options);
81 else {
82 ERROR1("Unrecognised authenticator type: \"%s\"", type);
83 return NULL;
86 if(!auth)
87 ERROR1("Couldn't configure authenticator of type \"%s\"", type);
89 return auth;
92 typedef struct {
93 char *filename;
94 } htpasswd_auth_state;
96 static void htpasswd_clear(auth_t *self) {
97 htpasswd_auth_state *state = self->state;
98 free(state->filename);
99 free(state);
100 free(self);
103 static int get_line(FILE *file, char *buf, int len)
105 if(fgets(buf, len, file)) {
106 int len = strlen(buf);
107 if(len > 0 && buf[len-1] == '\n') {
108 buf[--len] = 0;
109 if(len > 0 && buf[len-1] == '\r')
110 buf[--len] = 0;
112 return 1;
114 return 0;
117 /* md5 hash */
118 static char *get_hash(char *data, int len)
120 struct MD5Context context;
122 MD5Init(&context);
124 MD5Update(&context, data, len);
126 unsigned char digest[16];
127 MD5Final(digest, &context);
129 return util_bin_to_hex(digest, 16);
132 #define MAX_LINE_LEN 512
134 /* Not efficient; opens and scans the entire file for every request */
135 static auth_result htpasswd_auth(auth_t *auth, char *username, char *password)
137 htpasswd_auth_state *state = auth->state;
138 FILE *passwdfile = fopen(state->filename, "rb");
139 char line[MAX_LINE_LEN];
140 char *sep;
142 if(passwdfile == NULL) {
143 WARN2("Failed to open authentication database \"%s\": %s",
144 state->filename, strerror(errno));
145 return AUTH_FAILED;
148 while(get_line(passwdfile, line, MAX_LINE_LEN)) {
149 if(!line[0] || line[0] == '#')
150 continue;
152 sep = strchr(line, ':');
153 if(sep == NULL) {
154 DEBUG0("No seperator in line");
155 continue;
158 *sep = 0;
159 if(!strcmp(username, line)) {
160 /* Found our user, now: does the hash of password match hash? */
161 char *hash = sep+1;
162 char *hashed_password = get_hash(password, strlen(password));
163 if(!strcmp(hash, hashed_password)) {
164 fclose(passwdfile);
165 free(hashed_password);
166 return AUTH_OK;
168 free(hashed_password);
169 /* We don't keep searching through the file */
170 break;
174 fclose(passwdfile);
176 return AUTH_FAILED;
179 static auth_t *auth_get_htpasswd_auth(config_options_t *options)
181 auth_t *authenticator = calloc(1, sizeof(auth_t));
183 authenticator->authenticate = htpasswd_auth;
184 authenticator->free = htpasswd_clear;
186 htpasswd_auth_state *state = calloc(1, sizeof(htpasswd_auth_state));
188 while(options) {
189 if(!strcmp(options->name, "filename"))
190 state->filename = strdup(options->value);
191 options = options->next;
194 if(!state->filename) {
195 free(state);
196 free(authenticator);
197 ERROR0("No filename given in options for authenticator.");
198 return NULL;
201 authenticator->state = state;
202 DEBUG1("Configured htpasswd authentication using password file %s",
203 state->filename);
205 return authenticator;