1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
|
/* flatfile-auth.c -- Simple authentication plug-in demonstrating its use case
*
* Copyright (C) 2013 David Sommerseth <dazo@users.sourceforge.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* @file flatfile-auth.c
* @author David Sommerseth <dazo@users.sourceforge.net>
* @date 2013-05-29
*
* @brief Simple example plug-in authenticating user passwords
* against a simple flat file "database"
*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <eurephia_nullsafe.h>
#include <eurephia_context.h>
#include <eurephia_log.h>
#include <eurephia_values.h>
#include <eurephia_authplugin_driver.h>
#include <passwd.h>
static ePluginInfo pluginfo = { .name = "flatfile authentication",
.version = "1.0",
.copyright = "2013 (C) David Sommerseth <dazo@users.sourceforge.net>",
.pluginType = eptAUTH,
.APIversion = 1 };
static eurephiaVALUES *config = NULL;
static eurephiaVALUES *passdb = NULL;
/**
* @copydoc PluginInfo()
*/
ePluginInfo * PluginInfo()
{
return &pluginfo;
}
/**
* @copydoc PluginInit()
*/
int PluginInit(eurephiaCTX *ctx, const char *args)
{
FILE *fp = NULL;
char line[4098];
config = eCreate_value_space(ctx, 80);
if( config == NULL ) {
eurephia_log(ctx, LOG_FATAL, 0, "Failed to initialise flatfile auth");
return 0;
}
eAdd_value(ctx, config, "password_file", args);
// Load all username/password hashes into memory - *NOT RECOMMENDED* in real production environments
fp = fopen(args, "r");
if( fp == NULL ) {
eFree_values(ctx, config);
eurephia_log(ctx, LOG_FATAL, 0, "flatfile-auth: Failed to open user/password file");
return 0;
}
passdb = eCreate_value_space(ctx, 81);
if( config == NULL ) {
eFree_values(ctx, config);
fclose(fp);
eurephia_log(ctx, LOG_FATAL, 0,
"flatfile-auth: Failed to allocate memory to "
"username/password database");
return 0;
}
memset(&line, 0, 4098);
while( fgets(line, 4096, fp) ) {
char *pw = strstr(line, "|");
if( pw != NULL ) {
char *eol = strstr(pw, "\n");
*eol = 0; // Simple strip of \n at end of records
*pw = 0; // Split the username and password using a NULL-terminator
pw++;
eAdd_value(ctx, passdb, line, pw);
} else {
eurephia_log(ctx, LOG_WARNING, 0,
"flatfile-auth: Failed to parse record (no delimiter): %s", line);
}
memset(&line, 0, 4098);
}
fclose(fp);
eurephia_log(ctx, LOG_INFO, 0, "flatfile auth initialised, using '%s' as user/password database", args);
return 1;
}
/**
* @copydoc PluginClose()
*/
void PluginClose(eurephiaCTX *ctx)
{
eFree_values(ctx, config);
eurephia_log(ctx, LOG_INFO, 0, "flatfile auth stopped");
}
/**
* @copydoc AuthenticateUser()
*/
eAuthResult * AuthenticateUser(eurephiaCTX *ctx, const char *username, const char *passwd)
{
char *pwhash = NULL;
eAuthResult *res = NULL;
DEBUG(ctx, 10, "flatfile-auth:AuthenticateUser('%s', 'xxxxxx')", username);
assert(passdb != NULL);
// Allocate result buffer
res = malloc_nullsafe(ctx, sizeof(eAuthResult)+2);
if( res == NULL ) {
return NULL;
}
// Look up password hash from in-memory password database
pwhash = eGet_value(passdb, username);
if( pwhash != NULL ) { // If found, verify the password
char *crpwd = eurephia_pwd_crypt(ctx, passwd, pwhash);
res->status = ((crpwd != NULL) && (strcmp(crpwd, pwhash) == 0) ? eAUTH_SUCCESS : eAUTH_FAILED);
if( res->status == eAUTH_FAILED ) {
res->msg = strdup("Wrong password");
}
free_nullsafe(ctx, crpwd);
} else { // If not found - fail
res->status = eAUTH_FAILED;
res->msg = malloc_nullsafe(ctx, strlen(username)+32);
snprintf(res->msg, strlen(username)+30, "flatfile username attempted: %s", username);
}
return res;
}
/**
* @copydoc ChangePassword()
*/
eAuthResult * ChangePassword(eurephiaCTX *ctx, const char *username,
const char *oldpass, const char *newpass)
{
eurephiaVALUES *pwentry = NULL, *rec = NULL;
char *crpwd = NULL;
eAuthResult *res = NULL;
FILE *fp = NULL;
DEBUG(ctx, 10, "flatfile-auth:ChangePassword('%s', 'xxxOLDxxx', 'xxxNEWxxx')", username);
assert((passdb != NULL) && (config != NULL));
// Allocate result buffer
res = malloc_nullsafe(ctx, sizeof(eAuthResult)+2);
if( res == NULL ) {
return NULL;
}
// Find the password entry
pwentry = eGet_valuestruct(passdb, username);
if( pwentry == NULL ) { // If not found --> assume new user.
eurephiaVALUES *newrec = eCreate_value_space(ctx, 81);
if( newrec == NULL ) {
res->status = eAUTH_PLGERROR;
res->msg = strdup("Internal failure when preparing new user entry");
return res;
}
newrec->key = strdup(username);
newrec->val = eurephia_pwd_crypt(ctx, oldpass, NULL);
eAdd_valuestruct(ctx, passdb, newrec);
} else {
// Verify the password hash for the existing user
crpwd = eurephia_pwd_crypt(ctx, oldpass, pwentry->val);
if( (crpwd != NULL) && (strcmp(crpwd, pwentry->val) == 0) ) { // Password correct - update database
// Get a new password hash
free_nullsafe(ctx, crpwd);
crpwd = eurephia_pwd_crypt(ctx, newpass, NULL);
if( crpwd == NULL ) {
res->status = eAUTH_PLGERROR;
res->msg = strdup("Failed to generate new password hash");
return res;
}
}
}
// Open the database file with write access
fp = fopen(eGet_value(config, "password_file"), "w");
if( fp == NULL ) {
res->status = eAUTH_PLGERROR;
res->msg = strdup("Failed to open password file with write access");
return res;
}
// Remove the old password hash from the memory database
// and replace it with the new one
free_nullsafe(ctx, pwentry->val);
pwentry->val = crpwd;
// Update the database file
rewind(fp);
for( rec = passdb; rec != NULL; rec = rec->next ) {
fprintf(fp, "%s|%s\n", rec->key, rec->val);
}
fclose(fp);
return res;
}
|