1 /*
2  * uhub - A tiny ADC p2p connection hub
3  * Copyright (C) 2007-2014, Jan Vidar Krey
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "plugin_api/handle.h"
21 #include "util/memory.h"
22 #include "util/list.h"
23 #include "util/misc.h"
24 #include "util/log.h"
25 #include "util/config_token.h"
26 
set_error_message(struct plugin_handle * plugin,const char * msg)27 static void set_error_message(struct plugin_handle* plugin, const char* msg)
28 {
29 	plugin->error_msg = msg;
30 }
31 
32 struct acl_data
33 {
34 	struct linked_list* users;
35 	char* file;
36 	int readonly;
37 	int exclusive;
38 };
39 
insert_user(struct linked_list * users,const char * nick,const char * pass,enum auth_credentials cred)40 static void insert_user(struct linked_list* users, const char* nick, const char* pass, enum auth_credentials cred)
41 {
42 	struct auth_info* data = (struct auth_info*) hub_malloc_zero(sizeof(struct auth_info));
43 	strncpy(data->nickname, nick, MAX_NICK_LEN);
44 	strncpy(data->password, pass, MAX_PASS_LEN);
45 	data->credentials = cred;
46 	list_append(users, data);
47 }
48 
free_acl(struct acl_data * data)49 static void free_acl(struct acl_data* data)
50 {
51 	if (!data)
52 		return;
53 
54 	if (data->users)
55 	{
56 		list_clear(data->users, hub_free);
57 		list_destroy(data->users);
58 	}
59 	hub_free(data->file);
60 	hub_free(data);
61 }
62 
parse_config(const char * line)63 static struct acl_data* parse_config(const char* line)
64 {
65 	struct acl_data* data = (struct acl_data*) hub_malloc_zero(sizeof(struct acl_data));
66 	struct cfg_tokens* tokens = cfg_tokenize(line);
67 	char* token = cfg_token_get_first(tokens);
68 
69 	if (!data)
70 		return 0;
71 
72 	// set defaults
73 	data->readonly = 1;
74 	data->exclusive = 0;
75 	data->users = list_create();
76 
77 	while (token)
78 	{
79 		char* split = strchr(token, '=');
80 		size_t len = strlen(token);
81 		size_t key = split ? (split - token) : len;
82 		if (key == 4 && strncmp(token, "file", 4) == 0)
83 		{
84 			if (data->file)
85 				hub_free(data->file);
86 			data->file = strdup(split + 1);
87 		}
88 		else if (key == 8 && strncmp(token, "readonly", 8) == 0)
89 		{
90 			if (!string_to_boolean(split + 1, &data->readonly))
91 				data->readonly = 1;
92 		}
93 		else if (key == 9 && strncmp(token, "exclusive", 9) == 0)
94 		{
95 			if (!string_to_boolean(split + 1, &data->exclusive))
96 				data->exclusive = 1;
97 		}
98 		else
99 		{
100 			cfg_tokens_free(tokens);
101 			free_acl(data);
102 			return 0;
103 		}
104 
105 		token = cfg_token_get_next(tokens);
106 	}
107 
108 	cfg_tokens_free(tokens);
109 	return data;
110 }
111 
parse_line(char * line,int line_count,void * ptr_data)112 static int parse_line(char* line, int line_count, void* ptr_data)
113 {
114 	struct linked_list* users = (struct linked_list*) ptr_data;
115 	struct cfg_tokens* tokens = cfg_tokenize(line);
116 	enum auth_credentials cred;
117 	char* credential;
118 	char* username;
119 	char* password;
120 
121 	if (cfg_token_count(tokens) == 0)
122 	{
123 		cfg_tokens_free(tokens);
124 		return 0;
125 	}
126 
127 	if (cfg_token_count(tokens) < 2)
128 	{
129 		cfg_tokens_free(tokens);
130 		return -1;
131 	}
132 
133 	credential = cfg_token_get_first(tokens);
134 	username   = cfg_token_get_next(tokens);
135 	password   = cfg_token_get_next(tokens);
136 
137 	if (!auth_string_to_cred(credential, &cred))
138 	{
139 		cfg_tokens_free(tokens);
140 		return -1;
141 	}
142 
143 	insert_user(users, username, password, cred);
144 	cfg_tokens_free(tokens);
145 	return 0;
146 }
147 
load_acl(const char * config,struct plugin_handle * handle)148 static struct acl_data* load_acl(const char* config, struct plugin_handle* handle)
149 {
150 
151 	struct acl_data* data = parse_config(config);
152 
153 	if (!data)
154 		return 0;
155 
156 	if (!data->file || !*data->file)
157 	{
158 		free_acl(data); data = 0;
159 		set_error_message(handle, "No configuration file given, missing \"file=<filename>\" configuration option.");
160 		return 0;
161 	}
162 
163 	if (file_read_lines(data->file, data->users, &parse_line) == -1)
164 	{
165 		fprintf(stderr, "Unable to load %s\n", data->file);
166 		set_error_message(handle, "Unable to load file");
167 	}
168 
169 	return data;
170 }
171 
unload_acl(struct acl_data * data)172 static void unload_acl(struct acl_data* data)
173 {
174 	free_acl(data);
175 }
176 
get_user(struct plugin_handle * plugin,const char * nickname,struct auth_info * data)177 static plugin_st get_user(struct plugin_handle* plugin, const char* nickname, struct auth_info* data)
178 {
179 	struct acl_data* acl = (struct acl_data*) plugin->ptr;
180 	struct auth_info* info;
181 	LIST_FOREACH(struct auth_info*, info, acl->users,
182 	{
183 		if (strcasecmp((char*)info->nickname, nickname) == 0)
184 		{
185 			memcpy(data, info, sizeof(struct auth_info));
186 			return st_allow;
187 		}
188 	});
189 	if (acl->exclusive)
190 		return st_deny;
191 	return st_default;
192 }
193 
register_user(struct plugin_handle * plugin,struct auth_info * user)194 static plugin_st register_user(struct plugin_handle* plugin, struct auth_info* user)
195 {
196 	struct acl_data* acl = (struct acl_data*) plugin->ptr;
197 	if (acl->exclusive)
198 		return st_deny;
199 	return st_default;
200 }
201 
update_user(struct plugin_handle * plugin,struct auth_info * user)202 static plugin_st update_user(struct plugin_handle* plugin, struct auth_info* user)
203 {
204 	struct acl_data* acl = (struct acl_data*) plugin->ptr;
205 	if (acl->exclusive)
206 		return st_deny;
207 	return st_default;
208 }
209 
delete_user(struct plugin_handle * plugin,struct auth_info * user)210 static plugin_st delete_user(struct plugin_handle* plugin, struct auth_info* user)
211 {
212 	struct acl_data* acl = (struct acl_data*) plugin->ptr;
213 	if (acl->exclusive)
214 		return st_deny;
215 	return st_default;
216 }
217 
plugin_register(struct plugin_handle * plugin,const char * config)218 PLUGIN_API int plugin_register(struct plugin_handle* plugin, const char* config)
219 {
220 	PLUGIN_INITIALIZE(plugin, "File authentication plugin", "0.1", "Authenticate users based on a read-only text file.");
221 
222 	// Authentication actions.
223 	plugin->funcs.auth_get_user = get_user;
224 	plugin->funcs.auth_register_user = register_user;
225 	plugin->funcs.auth_update_user = update_user;
226 	plugin->funcs.auth_delete_user = delete_user;
227 
228 	plugin->ptr = load_acl(config, plugin);
229 	if (plugin->ptr)
230 		return 0;
231 	return -1;
232 }
233 
plugin_unregister(struct plugin_handle * plugin)234 PLUGIN_API int plugin_unregister(struct plugin_handle* plugin)
235 {
236 	set_error_message(plugin, 0);
237 	unload_acl(plugin->ptr);
238 	return 0;
239 }
240 
241