diff options
author | David Sommerseth <dazo@users.sourceforge.net> | 2013-06-08 02:32:34 +0200 |
---|---|---|
committer | David Sommerseth <dazo@users.sourceforge.net> | 2013-06-09 01:03:29 +0200 |
commit | 6554cba9441de42e0c5c455b16fb5f6b39c19e28 (patch) | |
tree | 027ed605d3c5556bba853018fd6eb6cf18effc24 /auth/socket/socket-auth.c | |
parent | d7b486079a77beb883e3c5e39842dd5c180f3b7b (diff) | |
download | eurephia-6554cba9441de42e0c5c455b16fb5f6b39c19e28.tar.gz eurephia-6554cba9441de42e0c5c455b16fb5f6b39c19e28.tar.xz eurephia-6554cba9441de42e0c5c455b16fb5f6b39c19e28.zip |
auth: Added socket-auth module
This can authenticate username/passwords via a file socket to
an authentication service.
A simple authentication service written in Python is added as well.
Signed-off-by: David Sommerseth <dazo@users.sourceforge.net>
Diffstat (limited to 'auth/socket/socket-auth.c')
-rw-r--r-- | auth/socket/socket-auth.c | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/auth/socket/socket-auth.c b/auth/socket/socket-auth.c new file mode 100644 index 0000000..41396fb --- /dev/null +++ b/auth/socket/socket-auth.c @@ -0,0 +1,224 @@ +/* socket-auth.c -- Authenticates user/password against a socket service + * + * The socket service retrieves the username and password and replies with + * PASS or FAIL. See the demo-auth-server.py for more info + * + * 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 socket-auth.c + * @author David Sommerseth <dazo@users.sourceforge.net> + * @date 2013-06-08 + * + * @brief Authenticate users using a socket based auth server + */ + +/* + * The wire protocol for the socket service is: + * + * The client sends: + * 1 byte - lenght of username + * x bytes - the username + * 1 byte - lenght of password + * x bytes - the password + * + * And now the server is expected to reply with: + * 4 bytes - containing the string FAIL or PASS + * + */ + +#include <sys/socket.h> +#include <sys/un.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <eurephia_nullsafe.h> +#include <eurephia_context.h> +#include <eurephia_log.h> +#include <eurephia_authplugin_driver.h> + +/* + * INTERNAL VARIABLES AND FUNCTIONS + */ + +static int authservfd = -1; +static struct sockaddr_un sockaddr; + +/** + * Send data to the remote end according to the wire protocol + * where the first byte is the length of data to be sent. Maximum + * 127 bytes can be transferred. + * + * @param fd Socket fd to send the data to + * @param msg Pointer to the string to be sent + * + * @return Returns 1 on success, otherwise 0 + */ +static int send_data(int fd, const char *msg) +{ + int msglen = strlen(msg); + char buf[130]; + + memset(&buf, 0, 130); + if( msglen > 127 ) { + msglen = 127; + } + snprintf(buf, msglen+1, "%c", (int) strlen(msg)); + if (write(fd, buf, strlen(buf)) != strlen(buf)) { + return 0; + } + + snprintf(buf, msglen+1, "%s", msg); + if (write(fd, buf, strlen(buf)) != strlen(buf)) { + return 0; + } + return 1; +} + + +/** + * Reads the server response and parses it. Anything except of 'PASS' is + * handled as a failure. But it expects the response to alwyas be 4 bytes. + * + * @param fd Socket fd where to read the response from + * + * @returns Returns 1 on successful authentication, otherwise 0. If less than 4 bytes + * was read it will return -1. In this case, it might be wise to reconnect to + * the server. + */ +static int parse_result(int fd) +{ + char buf[6]; + + memset(&buf, 0, 6); + int r = read(fd, &buf, 4); + + if( r == 4 ) { + return strcmp(buf, "PASS") == 0; + } + return -1; +} + + +/** + * Sends username and password via the socket to the authentication server and + * parses the result back. + * + * @param fd Socket fd to the authentication server + * @param username Username to be authenticated + * @param passwd Matching password to the username + * + * @returns See parse_result() for valid result codes. + */ +static int authenticate_user(int fd, const char *username, const char *passwd) +{ + if( !send_data(fd, username) ) { + return 0; + } + if( !send_data(fd, passwd) ) { + return 0; + } + return parse_result(fd); +} + + +/* + * Required plug-in functions + */ + +static ePluginInfo pluginfo = { .name = "socket-auth plug-in", + .version = "1.0", + .copyright = "2013 (C) David Sommerseth <dazo@users.sourceforge.net>", + .pluginType = eptAUTH, + .APIversion = 1 }; + + +/** + * @copydoc PluginInfo() + */ +ePluginInfo * PluginInfo() +{ + return &pluginfo; +} + +/** + * @copydoc PluginInit() + */ +int PluginInit(eurephiaCTX *ctx, const char *args) +{ + authservfd = socket(AF_UNIX, SOCK_STREAM, 0); + if ( authservfd == -1 ) { + eurephia_log(ctx, LOG_FATAL, 0, "Failed to initialise socket to the socket-auth server"); + return 0; + } + + memset(&sockaddr, 0, sizeof(struct sockaddr_un)); + sockaddr.sun_family = AF_UNIX; + strncpy(sockaddr.sun_path, args, sizeof(sockaddr.sun_path)-1); + + if( connect(authservfd, (struct sockaddr*)&sockaddr, sizeof(struct sockaddr_un)) == -1) { + eurephia_log(ctx, LOG_FATAL, 0, "Failed to connect to the socket-auth server"); + close(authservfd); + authservfd = -1; + return 0; + } + + eurephia_log(ctx, LOG_INFO, 0, "socket-auth connected via %s", args); + return 1; +} + + +/** + * @copydoc PluginClose() + */ +void PluginClose(eurephiaCTX *ctx) +{ + send_data(authservfd, "***SHUTDOWN***"); + close(authservfd); + eurephia_log(ctx, LOG_INFO, 0, "Disconnected from auth-socket"); +} + + +/** + * @copydoc AuthenticateUser() + */ +eAuthResult * AuthenticateUser(eurephiaCTX *ctx, const char *username, const char *passwd) +{ + eAuthResult *ret = NULL; + int authres = -2; + + DEBUG(ctx, 20, "socket-auth:AuthenticateUser('%s', xxxxxx)", username); + + ret = malloc_nullsafe(ctx, sizeof(eAuthResult)+2); + authres = authenticate_user(authservfd, username, passwd); + if( authres < 0 ) { + ret->status = eAUTH_PLGERROR; + ret->msg = strdup("Failed communicating with auth-server"); + } else if( authres == 0 ) { + ret->status = eAUTH_FAILED; + ret->msg = strdup("Wrong password"); + } else if( authres == 1 ) { + ret->status = eAUTH_SUCCESS; + } else { + // This should never ever happen + ret->status = eAUTH_PLGERROR; + ret->msg = strdup("Unknown result code"); + } + return ret; +} |