From d2f0741fd4814189838e344f03f995c892aeb107 Mon Sep 17 00:00:00 2001 From: Gergely Polonkai Date: Wed, 27 Apr 2016 20:35:44 +0200 Subject: [PATCH] Initial --- Makefile | 38 +++ PROTO | 77 ++++++ README | 5 + common.c | 189 +++++++++++++++ context.c | 48 ++++ data.c | 251 ++++++++++++++++++++ functions.h | 35 +++ logging.c | 63 +++++ main.c | 116 +++++++++ misc.c | 162 +++++++++++++ networking.c | 645 +++++++++++++++++++++++++++++++++++++++++++++++++++ signal.c | 88 +++++++ userv.h | 86 +++++++ 13 files changed, 1803 insertions(+) create mode 100644 Makefile create mode 100644 PROTO create mode 100644 README create mode 100644 common.c create mode 100644 context.c create mode 100644 data.c create mode 100644 functions.h create mode 100644 logging.c create mode 100644 main.c create mode 100644 misc.c create mode 100644 networking.c create mode 100644 signal.c create mode 100644 userv.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..43ac247 --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +CC = gcc +CFLAGS = -Wall -c -o +LDFLAGS = -Wall -lcrypt -o +EXE = userv +RM = rm -f + +OBJECTS = main.o data.o networking.o misc.o common.o logging.o signal.o context.o + +all: $(OBJECTS) + $(CC) $(LDFLAGS) $(EXE) $(OBJECTS) + +clean: + $(RM) $(OBJECTS) $(EXE) + +main.o: main.c + $(CC) $(CFLAGS) main.o main.c + +data.o: data.c + $(CC) $(CFLAGS) data.o data.c + +networking.o: networking.c + $(CC) $(CFLAGS) networking.o networking.c + +misc.o: misc.c + $(CC) $(CFLAGS) misc.o misc.c + +common.o: common.c + $(CC) $(CFLAGS) common.o common.c + +logging.o: logging.c + $(CC) $(CFLAGS) logging.o logging.c + +signal.o: signal.c + $(CC) $(CFLAGS) signal.o signal.c + +context.o: context.c + $(CC) $(CFLAGS) context.o context.c + diff --git a/PROTO b/PROTO new file mode 100644 index 0000000..dcdf162 --- /dev/null +++ b/PROTO @@ -0,0 +1,77 @@ +Lines beginning with "S:" are server messages. +Lines beginning with "C:" are client messages. + +S: +C: +If the client is from an allowed IP: +S: R +Or else: +S: D +S: + +From now on, we assume that a connection is already built to the server + +C: L +If the client is already logged in: +S: L +If uname or pass is missing: +S: E +If the specified user is not allowed to login: +S: D +If the specified uname/pass combination is bad: +S: B +If login successful: +S: S + +C: Q +S: S +S: + +C: U +If client hasn't login yet: +S: L +If uid is not numeric: +S: E +If uid is used: +S: U +If uid is free: +S:F + +C: N +If client hasn't login yet: +S: L +If uname exists: +S: U +If uname doesn't exist: +S: F + +C: A ::::: +If client hasn't login yet: +S: L +If uid, teacher?, samba?, passwd or comment is not specified +S: E +If uid is not numeric: +S: E +If uid or uname is used: +S: E +If teacher? not 0 nor 1, and samba? not 0 nor 1 +S: E +If tempfile or scriptfile couldn't be created: +S: F +If user couldn't be created: +S: F +If user has been created: +S: S + +C: D +If client hasn't login yet: +S: L +If uname doesn't exist: +S: E +If scriptfile couldn't be created: +S: F +If user cannot be deleted: +S: F +If user is deleted: +S: S + diff --git a/README b/README new file mode 100644 index 0000000..f945d6d --- /dev/null +++ b/README @@ -0,0 +1,5 @@ +This project is a high-school attempt to create centralized user +management, long before I heard about LDAP and the likes. + +I release this as a public domain, I guess you can learn this-and-that +from it. \ No newline at end of file diff --git a/common.c b/common.c new file mode 100644 index 0000000..6010f3d --- /dev/null +++ b/common.c @@ -0,0 +1,189 @@ +/* + * UserServer/0.1 + * common.c - Common functions + * + * Copyright (C) 2002 Gergely Polonkai + * Copyright (C) 2002-2006 P-Team Programmers' Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 recieved a copy of the GNU General Public License + * along with this program; if not, write to Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. + * + * GNU GPL is in doc/COPYING + */ + +#include +#include +#include +#include +#include +#include + +#include "userv.h" +#include "functions.h" + +char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +int +ParseConfig(void) { + FILE *cf; + char buf[1024]; + char *line; + int nl = 0; + + if ((cf = fopen("/etc/userv.conf", "r")) == NULL) + return ERR_NOCF; + + memset(&buf, 0, 1024); + while (fgets((char *)&buf, 1023, cf)) { + char *param; + int i; + + nl++; + if ((line = trim(buf, NULL))) { + if (strncmp(line, "listen ", 7) == 0) { + param = strchr(line, ' ') + 1; + for (i = 0; i < strlen(param); i++) + if (isspace(*(param + i))) { + *(param + i) = 0; + break; + } + if (!valid_ip(param)) + return nl; + if (AddListen(param) != ERR_OK) + return ERR_NOMEM; + } + if (strncmp(line, "confserv ", 9) == 0) { + param = strchr(line, ' ') + 1; + for (i = 0; i < strlen(param); i++) + if (isspace(*(param + 1))) { + *(param + i) = 0; + break; + } + if (!valid_ip(param)) + return nl; + if (AddConfig(param) != ERR_OK) + return ERR_NOMEM; + } + if (strncmp(line, "server ", 7) == 0) { + param = strchr(line, ' ') + 1; + for (i = 0; i < strlen(param); i++) + if (isspace(*(param + 1))) { + *(param + i) = 0; + break; + } + if (!valid_ip(param)) + return nl; + if (AddPeer(param) != ERR_OK) + return ERR_NOMEM; + } + if (strncmp(line, "client ", 7) == 0) { + param = strchr(line, ' ') + 1; + for (i = 0; i < strlen(param); i++) + if (isspace(*(param + i))) { + *(param + i) = 0; + break; + } + if (!valid_ip(param)) + return nl; + if (AddClient(param) != ERR_OK) + return ERR_NOMEM; + } + if (strncmp(line, "user ", 5) == 0) { + param = strchr(line, ' ') + 1; + for (i = 0; i < strlen(param); i++) + if (isspace(*(param + i))) { + *(param + i) = 0; + break; + } + if (!valid_user(param)) + return nl; + if (AddUser(param) != ERR_OK) + return ERR_NOMEM; + } + free(line); + } + memset(buf, 0, 1024); + } + fclose(cf); + + return ERR_OK; +} + +int +Is_UID_exist(uid_t uid) { + if (getpwuid(uid) == NULL) + return 0; + return 1; +} + +int +pwcheck(char *uname, char *passw) { + struct passwd *pwentry; + char buf[1024]; + FILE *fd; + char *pwd; + + if ((pwentry = getpwnam(uname)) == NULL) + return ERR_NOUSER; + + if (strcmp(pwentry->pw_passwd, "x") == 0) { + if ((fd = fopen("/etc/shadow", "r")) == NULL) + return ERR_NOSHADOW; + + memset(&buf, 0, 1024); + while (fgets((char *)&buf, 1023, fd)) { + if (strncmp((char *)&buf, uname, strlen(uname)) == 0) + break; + memset(&buf, 0, 1024); + } + fclose(fd); + } else + strcpy((char *)&buf, pwentry->pw_passwd); + + pwd = strchr((char *)&buf, ':') + 1; + if (pwd - 1 == NULL) + return ERR_NOPASS; + + *(strchr(pwd, ':')) = 0; + + if (strcmp(crypt(passw, pwd), pwd) == 0) + return ERR_OK; + + return ERR_BADPASS; +} + +void +salt(char *where) { + int i; + if (!where) + return; + + strncpy(where, "$1$", 3); + for (i = 3; i < 11; i++) + where[i] = table[(int)(1.0 * strlen(table) * rand() / (RAND_MAX + 1.0))]; + where[11] = '$'; + where[12] = 0; +} + +void +tempname(char *where, size_t len) { + int i; + if (!where) + return; + + for (i = 0; i < len; i++) + where[i] = table[(int)(1.0 * strlen(table) * rand() / (RAND_MAX + 1.0))]; + where[len] = 0; +} + diff --git a/context.c b/context.c new file mode 100644 index 0000000..5796a42 --- /dev/null +++ b/context.c @@ -0,0 +1,48 @@ +/* + * UserServer/0.1 + * context.c - Context debugging + * + * Copyright (C) 2002 Gergely Polonkai + * Copyright (C) 2002-2006 P-Team Programmers' Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 recieved a copy of the GNU General Public License + * along with this program; if not, write to Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. + * + * GNU GPL is in doc/COPYING + */ + +#include "userv.h" +#include "functions.h" + +#ifdef CONTEXT_DEBUG +# include +# include + +char fn[40] = ""; +int ln = 0; + +void +n_Context(char *fname, int line) { + memset(&fn, 0, 40); + strncpy((char *)&fn, fname, 39); + ln = line; +} + +void +n_PrintContext(void) { + Log(MT_MSG, "Last context was at %s:%d", fn, ln); +} + +#endif + diff --git a/data.c b/data.c new file mode 100644 index 0000000..e217697 --- /dev/null +++ b/data.c @@ -0,0 +1,251 @@ +/* + * UserServer/0.1 + * data.c - Handling local data + * + * Copyright (C) 2002 Gergely Polonkai + * Copyright (C) 2002-2006 P-Team Programmers' Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 recieved a copy of the GNU General Public License + * along with this program; if not, write to Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. + * + * GNU GPL is in doc/COPYING + */ + +#include +#include +#include + +#include "userv.h" +#include "functions.h" + +int +AddListen(char *IP) { + LST *temp; + char *ip; + + if ((ip = strdup(IP)) == NULL) + return ERR_NOMEM; + + if (laddr) { + temp = laddr; + while (temp->next) + temp = temp->next; + if ((temp->next = malloc(LSTS)) == NULL) + return ERR_NOMEM; + temp->next->next = NULL; + temp->next->IP = ip; + } else { + if ((laddr = malloc(LSTS)) == NULL) + return ERR_NOMEM; + laddr->next = NULL; + laddr->IP = ip; + } + + return ERR_OK; +} + +int +AddConfig(char *IP) { + SST *temp; + char *ip; + + if ((ip = strdup(IP)) == NULL) + return ERR_NOMEM; + + if (saddr) { + temp = saddr; + while (temp->next) + temp = temp->next; + if ((temp->next = malloc(SSTS)) == NULL) + return ERR_NOMEM; + temp->next->next = NULL; + temp->next->IP = ip; + } else { + if ((saddr = malloc(SSTS)) == NULL) + return ERR_NOMEM; + saddr->next = NULL; + saddr->IP = ip; + } + + return ERR_OK; +} + +int +AddPeer(char *IP) { + PST *temp; + char *ip; + + if ((ip = strdup(IP)) == NULL) + return ERR_NOMEM; + + if (paddr) { + temp = paddr; + while (temp->next) + temp = temp->next; + if ((temp->next = malloc(SSTS)) == NULL) + return ERR_NOMEM; + temp->next->next = NULL; + temp->next->IP = ip; + } else { + if ((paddr = malloc(SSTS)) == NULL) + return ERR_NOMEM; + paddr->next = NULL; + paddr->IP = ip; + } + + return ERR_OK; +} + +int +AddClient(char *IP) { + CST *temp; + char *ip; + + if ((ip = strdup(IP)) == NULL) + return ERR_NOMEM; + + if (caddr) { + temp = caddr; + while (temp->next) + temp = temp->next; + if ((temp->next = malloc(CSTS)) == NULL) + return ERR_NOMEM; + temp->next->next = NULL; + temp->next->IP = ip; + } else { + if ((caddr = malloc(CSTS)) == NULL) + return ERR_NOMEM; + caddr->next = NULL; + caddr->IP = ip; + } + + return ERR_OK; +} + +int +AddUser(char *name) { + UST *temp; + char *un; + + if ((un = strdup(name)) == NULL) + return ERR_NOMEM; + + if (auser) { + temp = auser; + while (temp->next) + temp = temp->next; + if ((temp->next = malloc(USTS)) == NULL) + return ERR_NOMEM; + temp->next->next = NULL; + temp->next->uname = un; + } else { + if ((auser = malloc(USTS)) == NULL) + return ERR_NOMEM; + auser->next = NULL; + auser->uname = un; + } + + return ERR_OK; +} + +void +CleanUp(int type) { + if (laddr) { + LST *temp; + temp = laddr->next; + if (laddr->IP) + free(laddr->IP); + free(laddr); + while (temp) { + LST *t = temp; + temp = temp->next; + if (t->IP) + free(t->IP); + free(t); + } + } + laddr = NULL; + + if (paddr) { + PST *temp; + temp = paddr->next; + if (paddr->IP) + free(paddr->IP); + free(paddr); + while (temp) { + PST *t = temp; + temp = temp->next; + if (t->IP) + free(t->IP); + free(t); + } + } + paddr = NULL; + + if (saddr) { + SST *temp; + temp = saddr->next; + if (saddr->IP) + free(saddr->IP); + free(saddr); + while (temp) { + SST *t = temp; + temp = temp->next; + if (t->IP) + free(t->IP); + free(t); + } + } + saddr = NULL; + + if (caddr) { + CST *temp; + temp = caddr->next; + if (caddr->IP) + free(caddr->IP); + free(caddr); + while (temp) { + CST *t = temp; + temp = temp->next; + if (t->IP) + free(t->IP); + free(t); + } + } + caddr = NULL; + + if (auser) { + UST *temp; + temp = auser->next; + if (auser->uname) + free(auser->uname); + free(auser); + while (temp) { + UST *t = temp; + temp = temp->next; + if (t->uname) + free(t->uname); + free(t); + } + } + auser = NULL; + + while (nconn) { + if ((nconn->sfd != -1) && (type == 0) && (nconn->type == CT_CLIENT)) + Send(nconn->sfd, "T\n"); + DelConn(nconn->sfd); + } + nconn = NULL; +} + diff --git a/functions.h b/functions.h new file mode 100644 index 0000000..abf4d5e --- /dev/null +++ b/functions.h @@ -0,0 +1,35 @@ +#ifndef _US_FUNCTIONS_H +# define _US_FUNCTIONS_H + +# include +# include "userv.h" + +int AddListen(char *); +int AddClient(char *); +int AddUser(char *); +int AddConfig(char *); +int AddPeer(char *); +void CleanUp(int); +int StartListening(void); +int valid_user(char *); +int valid_ip(char *); +char *trim(char *, char *); +int ip_allowed(char *); +int MainLoop(void); +int ParseConfig(void); +int pwcheck(char *, char *); +int IsNum(char *); +int Is_UID_exist(uid_t); +void salt(char *); +void tempname(char *, size_t); +int user_allowed(char *); +void Log(int, char *, ...); +void SetSignals(void); +void Send(int, char *, ...); +void DelConn(int); +# ifdef CONTEXT_DEBUG +void n_Context(char *, int); +void n_PrintContext(void); +# endif + +#endif /* _US_FUNCTIONS_H */ diff --git a/logging.c b/logging.c new file mode 100644 index 0000000..3f530da --- /dev/null +++ b/logging.c @@ -0,0 +1,63 @@ +/* + * UserServer/0.1 + * logging.c - Logging facility + * + * Copyright (C) 2002 Gergely Polonkai + * Copyright (C) 2002-2006 P-Team Programmers' Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 recieved a copy of the GNU General Public License + * along with this program; if not, write to Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. + * + * GNU GPL is in doc/COPYING + */ + +#include +#include +#include +#include +#include + +#include "userv.h" +#include "functions.h" + +static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +void +Log(int type, char *fmt, ...) { + char buf1[256]; + va_list ap; + FILE *lf; + int prior; + time_t now; + struct tm *tm; + + va_start(ap, fmt); + vsnprintf(buf1, 255, fmt, ap); + va_end(ap); + if ((lf = fopen("/var/log/userv.log", "a")) != NULL) { + now = time(NULL); + tm = localtime((const time_t *)&now); + + fprintf(lf, "%s %2d %02d:%02d:%02d UserServer[%d] %s: %s\n", month[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, getpid(), (type == MT_ERROR) ? "ERR" : "MSG", buf1); + + fclose(lf); + } + + openlog("UserServer", LOG_PID, LOG_DAEMON); + prior = LOG_DAEMON; + prior |= (type == MT_ERROR) ? LOG_ERR : LOG_NOTICE; + syslog(prior, "%s: %s", (type == MT_ERROR) ? "ERR" : "MSG", buf1); + closelog(); +} + diff --git a/main.c b/main.c new file mode 100644 index 0000000..11f4da4 --- /dev/null +++ b/main.c @@ -0,0 +1,116 @@ +/* + * UserServer/0.1 + * main.c - Main facility + * + * Copyright (C) 2002 Gergely Polonkai + * Copyright (C) 2002-2006 P-Team Programmers' Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 recieved a copy of the GNU General Public License + * along with this program; if not, write to Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. + * + * GNU GPL is in doc/COPYING + */ + +#define USERV_MAIN + +#include +#include +#include +#include +#include + +#include "userv.h" +#include "functions.h" + +LST *laddr = NULL; +CST *caddr = NULL; +UST *auser = NULL; +NST *nconn = NULL; +SST *saddr = NULL; +PST *paddr = NULL; + +int +main(void) { + int t; + struct timeval tv; + FILE *pf; + + SetSignals(); + + if (daemon(1, 0) == -1) { + Log(MT_ERROR, "Couldn't detach from controlling terminal"); + CleanUp(0); + unlink("/var/run/userv.pid"); + return -1; + } + + if ((pf = fopen("/var/run/userv.pid", "w")) == NULL) { + Log(MT_ERROR, "Unable to create pidfile"); + return -1; + } + fprintf(pf, "%d\n", getpid()); + fclose(pf); + + if (gettimeofday(&tv, NULL) != 0) { + Log(MT_ERROR, "Unable to get system time"); + unlink("/var/run/userv.pid"); + return -1; + } + srand(tv.tv_usec); + + if (geteuid() != 0) { + Log(MT_ERROR, "This server MUST be run as root!"); + unlink("/var/run/userv.pid"); + return -1; + } + + t = ParseConfig(); + if (t != 0) { + CleanUp(0); + unlink("/var/run/userv.pid"); + } + if (t > 0) { + Log(MT_ERROR, "Erronous line at /etc/userv.conf:%d", t); + return -1; + } else if (t < 0) { + switch (ParseConfig()) { + case ERR_NOCF: + Log(MT_ERROR, "Config file /etc/userv.conf doesn't exist"); + return -1; + case ERR_NOMEM: + Log(MT_ERROR, "Not enough memory while processing /etc/userv.conf"); + return -1; + default: + Log(MT_ERROR, "Undefined error\n"); + return -2; + } + } + + if (StartListening() != ERR_OK) { + Log(MT_ERROR, "Error occured while starting networking"); + CleanUp(0); + unlink("/var/run/userv.pid"); + return -1; + } + + if (MainLoop() != ERR_OK) + Log(MT_ERROR, "Error during loop"); + + unlink("/var/run/userv.pid"); + + CleanUp(0); + + return 0; +} + diff --git a/misc.c b/misc.c new file mode 100644 index 0000000..ec76617 --- /dev/null +++ b/misc.c @@ -0,0 +1,162 @@ +/* + * UserServer/0.1 + * misc.c - Miscellanous functions + * + * Copyright (C) 2002 Gergely Polonkai + * Copyright (C) 2002-2006 P-Team Programmers' Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 recieved a copy of the GNU General Public License + * along with this program; if not, write to Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. + * + * GNU GPL is in doc/COPYING + */ + +#include +#include +#include +#include + +#include "userv.h" +#include "functions.h" + +char *trim(char *text, char *spc) { + int start, end; + char *b; + + if (spc) { + for (start = 0; start < strlen(text); start++) + if (!strchr(spc, *(text + start))) + break; + for (end = strlen(text) - 1; end >= 0; end--) + if (!strchr(spc, *(text + end))) + break; + } else { + for (start = 0; start < strlen(text); start++) + if (!isspace(*(text + start))) + break; + for (end = strlen(text) - 1; end >= 0; end--) + if (!isspace(*(text + end))) + break; + } + if (end == -1) + return NULL; + + if ((b = malloc(end - start + 2)) == NULL) + return NULL; + memset(b, 0, end - start + 2); + + strncpy(b, text + start, end - start + 1); + + return b; +} + +int +valid_ip(char *addr) { + int i, np = 0, nn = 0; + + if (!addr) + return 0; + + if (strlen(addr) > 15) + return 0; + + if (!isdigit(addr[0])) + return 0; + + for (i = 0; i < strlen(addr); i++) { + if (*(addr + i) == '.') + np++; + if ((*(addr + i) != '.') && (!isdigit(*(addr + i)))) + return 0; + } + + if (np != 3) + return 0; + + np = 0; + + for (i = 0; i < strlen(addr); i++) { + if (*(addr + i) == '.') { + if (np) + return 0; + np = 1; + nn = 0; + } + if (*(addr + i) != '.') { + np = 0; + nn++; + if (nn == 4) + return 0; + } + if (i > 0) + if ((*(addr + i - 1) == '0') && (*(addr + i) != '.')) + return 0; + } + + if (strcmp(addr, "0.0.0.0") == 0) + return 0; + + if (strcmp(addr, "255.255.255.255") == 0) + return 0; + + return 1; +} + +int +valid_user(char *name) { + if (getpwnam(name) == NULL) + return 0; + return 1; +} + +int +ip_allowed(char *IP) { + CST *temp = caddr; + while (temp) { + if (strcmp(IP, temp->IP) == 0) + return 1; + temp = temp->next; + } + return 0; +} + +int +user_allowed(char *uname) { + UST *temp = auser; + + if (strcmp(uname, "root") == 0) + return 0; + + while (temp) { + if (strcmp(uname, temp->uname) == 0) + return 1; + temp = temp->next; + } + return 0; +} + +int +IsNum(char *str) { + int i; + + if (!str) + return 0; + + for (i = 0; i < strlen(str); i++) + if (!isdigit(*(str + i))) + return 0; + + return 1; +} + diff --git a/networking.c b/networking.c new file mode 100644 index 0000000..a35e1ee --- /dev/null +++ b/networking.c @@ -0,0 +1,645 @@ +/* + * UserServer/0.1 + * networking.c - Handling network connections + * + * Copyright (C) 2002 Gergely Polonkai + * Copyright (C) 2002-2006 P-Team Programmers' Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 recieved a copy of the GNU General Public License + * along with this program; if not, write to Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. + * + * GNU GPL is in doc/COPYING + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "userv.h" +#include "functions.h" + +fd_set master, readable; +int maxfd = 0; + +int +AddConn(int type, int sfd, char *IP) { + char *ip; + + if ((ip = strdup(IP)) == NULL) + return ERR_NOMEM; + + if (nconn) { + NST *temp = nconn; + while (temp->next) + temp = temp->next; + if ((temp->next = malloc(NSTS)) == NULL) { + free(ip); + return ERR_NOMEM; + } + temp->next->next = NULL; + temp->next->IP = ip; + temp->next->type = type; + temp->next->sfd = sfd; + temp->next->timeout = 0; + temp->next->loggedin = 0; + } else { + if ((nconn = malloc(NSTS)) == NULL) { + free(ip); + return ERR_NOMEM; + } + nconn->next = NULL; + nconn->IP = ip; + nconn->type = type; + nconn->sfd = sfd; + nconn->timeout = 0; + nconn->loggedin = 0; + } + FD_SET(sfd, &master); + if (sfd > maxfd) + maxfd = sfd; + return ERR_OK; +} + +void +DelConn(int sfd) { + NST *temp = nconn; + NST *p = NULL; + NST *n; + + while (temp) { + n = temp->next; + if (temp->sfd == sfd) { + if (temp->IP) + free(temp->IP); + if (sfd != -1) + close(sfd); + if (p) + p->next = temp->next; + else + nconn = n; + free(temp); + FD_CLR(sfd, &master); + return; + } + p = temp; + temp = temp->next; + } +} + +int +Type(int sfd) { + NST *temp = nconn; + while (temp) { + if (temp->sfd == sfd) + return temp->type; + temp = temp->next; + } + return CT_NONE; +} + +int +LoggedIn(int sfd) { + NST *temp = nconn; + while (temp) { + if (temp->sfd == sfd) + return temp->loggedin; + temp = temp->next; + } + return 0; +} + +int +SetLogin(int sfd, char *uname) { + if (uname) { + char *un; + NST *temp = nconn; + + if ((un = strdup(uname)) == NULL) + return ERR_NOMEM; + else { + while (temp) { + if (temp->sfd == sfd) { + temp->loggedin = 1; + temp->uname = un; + return ERR_OK; + } + temp = temp->next; + } + } + } + + return ERR_NOUSER; +} + +char * +GetIP(int sfd) { + NST *temp = nconn; + + while (temp) { + if (temp->sfd == sfd) + return temp->IP; + temp = temp->next; + } + return NULL; +} + +char * +GetUser(int sfd) { + NST *temp = nconn; + + while (temp) { + if (temp->sfd == sfd) + return temp->uname; + temp = temp->next; + } + return NULL; +} + +void +IncTimeout(int sfd) { + NST *temp = nconn; + while (temp) { + if (temp->sfd == sfd) { + temp->timeout++; + return; + } + if (temp->timeout == 600) { + Log(MT_MSG, "Timeout at %s", GetIP(sfd)); + DelConn(temp->sfd); + return; + } + temp = temp->next; + } +} + +int +StartListening(void) { + { + LST *temp; + + FD_ZERO(&master); + FD_ZERO(&readable); + + temp = laddr; + while (temp) if (temp->IP) { + int sfd; + struct sockaddr_in la; + int yes = 1; + + if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + return ERR_SOCKET; + if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) + return ERR_OPT; + + la.sin_family = AF_INET; + la.sin_addr.s_addr = inet_addr(temp->IP); + la.sin_port = htons(8778); + memset(&(la.sin_zero), 0, 8); + + if (bind(sfd, (struct sockaddr *)&la, sizeof(la)) == -1) + return ERR_BIND; + + if (listen(sfd, 10) == -1) + return ERR_LISTEN; + + if (AddConn(CT_LISTEN, sfd, temp->IP) != ERR_OK) + return ERR_NOMEM; + + temp = temp->next; + } + } + + { + SST *temp; + + temp = saddr; + while (temp) if (temp->IP) { + int sfd; + struct sockaddr_in la; + int yes = 1; + + if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + return ERR_SOCKET; + if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) + return ERR_OPT; + + la.sin_family = AF_INET; + la.sin_addr.s_addr = inet_addr(temp->IP); + la.sin_port = htons(8777); + memset(&(la.sin_zero), 0, 8); + + if (bind(sfd, (struct sockaddr *)&la, sizeof(la)) == -1) + return ERR_BIND; + + if (listen(sfd, 10) == -1) + return ERR_LISTEN; + + if (AddConn(CT_CONFIG, sfd, temp->IP) != ERR_OK) + return ERR_NOMEM; + + temp = temp->next; + } + } + + return ERR_OK; +} + +void +Send(int sfd, char *msg, ...) { + va_list ap; + + va_start(ap, msg); + vdprintf(sfd, msg, ap); + va_end(ap); +} + +int +MainLoop(void) { + struct timeval tv; + + while (1) { + int t; + readable = master; + tv.tv_sec = 1; + tv.tv_usec = 0; + + t = select(maxfd + 1, &readable, NULL, NULL, &tv); + if (t != -1) { + int i; + + for (i = 0; i <= maxfd; i++) { + if (FD_ISSET(i, &readable)) { + if (Type(i) == CT_LISTEN) { + struct sockaddr_in ra; + int al = sizeof(ra); + int nfd; + + if ((nfd = accept(i, (struct sockaddr *)&ra, &al)) != -1) { + if (ip_allowed(inet_ntoa(ra.sin_addr))) { + AddConn(CT_CLIENT, nfd, inet_ntoa(ra.sin_addr)); + Log(MT_MSG, "Connection from allowed IP %s", inet_ntoa(ra.sin_addr)); + Send(nfd, "R\n"); + } else { + Send(nfd, "D\n"); + Log(MT_MSG, "Attempted connection from denied IP %s", inet_ntoa(ra.sin_addr)); + close(nfd); + } + } + } + if (Type(i) == CT_CONFIG) { + struct sockaddr_in ra; + int al = sizeof(ra); + int nfd; + + if ((nfd = accept(i, (struct sockaddr *)&ra, &al)) != -1) { + if (ip_allowed(inet_ntoa(ra.sin_addr))) { + PST *temp = paddr->next; + Send(nfd, "P %s\n", paddr->IP); + while (temp) { + Send(nfd, "P %s\n", temp->IP); + temp = temp->next; + } + Send(nfd, "S\n"); + close(nfd); + Log(MT_MSG, "Sent configuration to %s", inet_ntoa(ra.sin_addr)); + } else { + Send(nfd, "D\n"); + Log(MT_MSG, "Attempted connection from denied IP %s", inet_ntoa(ra.sin_addr)); + close(nfd); + } + } + } + if (Type(i) == CT_CLIENT) { + int r; + char buf[1024]; + + memset(&buf, 0, 1024); + r = recv(i, &buf, 1023, 0); + if (r == 0) { + Log(MT_MSG, "Connection closed from %s", GetIP(i)); + DelConn(i); + } + if (r > 0) { + char *line = trim(buf, NULL); + if (line) { + if (strncmp(line, "L ", 2) == 0) { + if (LoggedIn(i)) + Send(i, "L\n"); + else { + char *uname, *passw; + int start; + + for (start = 1; start < strlen(line); start++) + if (isspace(*(line + start))) + break; + uname = trim(line + start, NULL); + + for (start = 1; start < strlen(uname); start++) + if (isspace(*(uname + start))) + break; + + passw = trim(uname + start, NULL); + + for (start = 0; start < strlen(uname); start++) + if (isspace(*(uname + start))) + *(uname + start) = 0; + + if (!uname || !passw) + Send(i, "E\n"); + else { + if (!user_allowed(uname)) { + Log(MT_MSG, "Attempted login by denied user %s from %s", uname, GetIP(i)); + Send(i, "D\n"); + } else { + if (pwcheck(uname, passw) != ERR_OK) { + Log(MT_MSG, "Login with bad password by %s from %s", uname, GetIP(i)); + Send(i, "B\n"); + } else { + if (SetLogin(i, uname) == ERR_OK) { + Log(MT_MSG, "Successful login by %s at %s", uname, GetIP(i)); + Send(i, "S\n"); + } else { + Log(MT_MSG, "Failed to log in user %s from %s", uname, GetIP(i)); + Send(i, "F\n"); + } + } + } + } + } + } + if (strcmp(line, "Q") == 0) { + Send(i, "S\n"); + Log(MT_MSG, "Quit from %s, by %s", GetIP(i), GetUser(i)); + DelConn(i); + } + if (strncmp(line, "U ", 2) == 0) { + if (!LoggedIn(i)) + Send(i, "L\n"); + else { + int start; + char *param; + + for (start = 2; start < strlen(line); start++) + if (!isspace(*(line + start))) + break; + param = line + start; + for (start = 0; start < strlen(param); start++) + if (isspace(*(param + start))) + break; + *(param + start) = 0; + if (!IsNum(param)) + Send(i, "E\n"); + else { + uid_t uid = (uid_t)atoi(param); + if (Is_UID_exist(uid)) + Send(i, "U\n"); + else + Send(i, "F\n"); + } + } + } + if (strncmp(line, "N ", 2) == 0) { + if (!LoggedIn(i)) + Send(i, "L\n"); + else { + int start; + char *param; + + for (start = 2; start < strlen(line); start++) + if (!isspace(*(line + start))) + break; + param = line + start; + for (start = 0; start < strlen(param); start++) + if (isspace(*(param + start))) + break; + *(param + start) = 0; + if (valid_user(param)) + Send(i, "U\n"); + else + Send(i, "F\n"); + } + } + if (strncmp(line, "A ", 2) == 0) { + if (!LoggedIn(i)) + Send(i, "L\n"); + else { + int start; + char *param; + + for (start = 2; start < strlen(line); start++) + if (!isspace(*(line + start))) + break; + param = trim(line + start, NULL); + if (param) { + char *uname, *c_uid, *tanar, *samba, *passwd, *comment; + + uname = param; + c_uid = strchr(uname, ':') + 1; + if (c_uid - 1 == NULL) + Send(i, "E\n"); + else { + *(strchr(uname, ':')) = 0; + tanar = strchr(c_uid, ':') + 1; + if (tanar - 1 == NULL) + Send(i, "E\n"); + else { + *(strchr(c_uid, ':')) = 0; + samba = strchr(tanar, ':') + 1; + if (samba - 1 == NULL) + Send(i, "E\n"); + else { + *(strchr(tanar, ':')) = 0; + passwd = strchr(samba, ':') + 1; + if (passwd - 1 == NULL) + Send(i, "E\n"); + else { + *(strchr(samba, ':')) = 0; + comment = strchr(passwd, ':') + 1; + if (comment - 1 == NULL) + Send(i, "E\n"); + else { + *(strchr(passwd, ':')) = 0; + if (!IsNum(c_uid)) + Send(i, "E\n"); + else { + uid_t uid; + + uid = (uid_t)atoi(c_uid); + if (Is_UID_exist(uid) || valid_user(uname)) + Send(i, "U\n"); + else { + if ((strcmp(tanar, "0") != 0) && (strcmp(tanar, "1") != 0) && (strcmp(samba, "0") != 0) && (strcmp(samba, "1") != 0)) + Send(i, "E\n"); + else { + char s[13], *cpass, tempfilename[13], scriptfilename[13]; + FILE *tf, *sf; + + if (strcmp(c_uid, "0") == 0) { + Log(MT_MSG, "Trying to add user with uid 0 from %s by %s", GetIP(i), GetUser(i)); + Send(i, "F\n"); + } else { + salt((char *)&s); + cpass = crypt(passwd, s); + tempname((char *)&tempfilename, 12); + tempname((char *)&scriptfilename, 12); + + if ((tf = fopen(tempfilename, "w")) == NULL) { + Log(MT_ERROR, "Unable to create tempfile (by %s at %s)", GetUser(i), GetIP(i)); + Send(i, "F\n"); + } else { + fprintf(tf, "%s\n%s\n", passwd, passwd); + fclose(tf); + + if ((sf = fopen(scriptfilename, "w")) == NULL) { + Log(MT_ERROR, "Unabke to create scriptfile (by %s at %s)", GetUser(i), GetIP(i)); + Send(i, "F\n"); + } else { + pid_t pid; + + fprintf(sf, "/usr/sbin/useradd -u %s -g %s -s %s %s-c \"%s\" -p %s %s > /dev/null 2>&1\n", c_uid, (*tanar == '1') ? "tanar" : "tanulo", (*samba == '1') ? "/bin/bash" : "/bin/false", (*samba == '1') ? "-m " : "", comment, cpass, uname); + fprintf(sf, "r1=$?\n"); + if (*samba == '1') { + fprintf(sf, "/usr/bin/smbpasswd -a -s %s < %s > /dev/null 2>&1\n", uname, tempfilename); + fprintf(sf, "r2=$?\n"); + fprintf(sf, "/usr/bin/smbpasswd -e %s > /dev/null 2>&1\n", uname); + fprintf(sf, "r3=$?\n"); + fprintf(sf, "if [ $r1 != 0 -o $r2 != 0 -o $r3 != 0 ]; then\n"); + } else + fprintf(sf, "if [ $r1 != 0 ]; then\n"); + fprintf(sf, " exit 1\n"); + fprintf(sf, "else\n"); + fprintf(sf, " exit 0\n"); + fprintf(sf, "fi\n"); + fclose(sf); + + if ((pid = fork()) == 0) + execl("/bin/sh", "sh", scriptfilename); + else { + int ec; + + waitpid(pid, &ec, 0); + if (ec == 0) { + Log(MT_MSG, "Added user %s with uid %s from %s by %s", uname, c_uid, GetIP(i), GetUser(i)); + Send(i, "S\n"); + } else { + Log(MT_MSG, "Failed to add user %s with uid %s from %s bye %s", uname, c_uid, GetIP(i), GetUser(i)); + Send(i, "F\n"); + } + + unlink(scriptfilename); + } + } + unlink(tempfilename); + } + } + } + } + } + } + } + } + } + } + } + } + } + if (strncmp(line, "D ", 2) == 0) { + if (!LoggedIn(i)) + Send(i, "L\n"); + else { + int start; + char *uname; + + for (start = 2; start < strlen(line); start++) + if (!isspace(*(line + start))) + break; + + uname = line + start; + for (start = 0; start < strlen(uname); start++) + if (isspace(*(uname + start))) { + *(uname + start) = 0; + break; + } + + if (!valid_user(uname)) + Send(i, "E\n"); + else { + FILE *sf; + char scriptfilename[13]; + + tempname((char *)&scriptfilename, 12); + if ((sf = fopen(scriptfilename, "w")) == NULL) + Send(i, "F\n"); + else { + pid_t pid; + fprintf(sf, "userdel -r %s > /dev/null 2>&1\n", uname); + fprintf(sf, "r=$?\n"); + fprintf(sf, "if [ $r = 12 -o $r = 0 ]; then\n"); + fprintf(sf, " r1=0\n"); + fprintf(sf, "else\n"); + fprintf(sf, " r1=1\n"); + fprintf(sf, "fi\n"); + fprintf(sf, "smbpasswd -x %s > /dev/null 2>&1\n", uname); + fprintf(sf, "r2=$?\n"); + fprintf(sf, "if [ $r1 != 0 -o $r2 != 0 ]; then\n"); + fprintf(sf, " exit 1\n"); + fprintf(sf, "else\n"); + fprintf(sf, " exit 0\n"); + fprintf(sf, "fi\n"); + fclose(sf); + + if ((pid = fork()) == 0) { //child + execl("/bin/sh", "sh", scriptfilename); + } else { //parent + int ec; + waitpid(pid, &ec, 0); + if (ec == 0) { + Log(MT_MSG, "Deleted user %s from %s by %s", uname, GetIP(i), GetUser(i)); + Send(i, "S\n"); + } else { + Log(MT_MSG, "Failed to delete %s from %s by %s", uname, GetIP(i), GetUser(i)); + Send(i, "F\n"); + } + unlink(scriptfilename); + } + } + } + } + } + } + } + } + } else + if (Type(i) == CT_CLIENT) + IncTimeout(i); + } + } + } + + return ERR_OK; +} + diff --git a/signal.c b/signal.c new file mode 100644 index 0000000..12607b0 --- /dev/null +++ b/signal.c @@ -0,0 +1,88 @@ +/* + * UserServer/0.1 + * signal.c - Signal handling + * + * Copyright (C) 2002 Gergely Polonkai + * Copyright (C) 2002-2006 P-Team Programmers' Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 recieved a copy of the GNU General Public License + * along with this program; if not, write to Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. + * + * GNU GPL is in doc/COPYING + */ + +#include +#include +#include +#include + +#include "userv.h" +#include "functions.h" + +int fcount = 0; + +void +rehash(int signum) { + Log(MT_MSG, "Signal caught, rehashing..."); + CleanUp(0); + ParseConfig(); + StartListening(); +} + +void +shutdown(int signum) { + Log(MT_MSG, "Signal caught, shutting down..."); + CleanUp(0); + unlink("/var/run/userv.pid"); + exit(0); +} + +void +fatal(int signum) { + if (signum == SIGSEGV) + Log(MT_ERROR, "segv"); + fcount++; + Log(MT_ERROR, "Fatal signal caught, terminating..."); + PrintContext; + unlink("/var/run/userv.pid"); + if (fcount > 1) + exit(1); + CleanUp(1); + exit(1); +} + +#define SA(x, y) memset(&sa, 0, sizeof(sa)); \ + sa.sa_handler = (y); \ + sigaction(x, &sa, NULL) +void +SetSignals(void) { + struct sigaction sa; + + SA(SIGHUP, &rehash); + SA(SIGINT, &shutdown); + SA(SIGQUIT, &shutdown); + SA(SIGILL, &fatal); + SA(SIGABRT, &shutdown); + SA(SIGFPE, &fatal); + SA(SIGSEGV, &fatal); + SA(SIGTERM, &shutdown); + SA(SIGUSR1, SIG_IGN); + SA(SIGUSR2, SIG_IGN); + SA(SIGPIPE, SIG_IGN); + SA(SIGCHLD, SIG_IGN); + SA(SIGTTIN, SIG_IGN); + SA(SIGTTOU, SIG_IGN); +} +#undef SA + diff --git a/userv.h b/userv.h new file mode 100644 index 0000000..92b5ce7 --- /dev/null +++ b/userv.h @@ -0,0 +1,86 @@ +#ifndef US_USERV_H +# define US_USERV_H + +# define CONTEXT_DEBUG +# ifdef CONTEXT_DEBUG +# define Context n_Context(__FILE__, __LINE__) +# define PrintContext n_PrintContext() +# else +# define Context +# define PrintContext +# endif + +# define ERR_OK 0 +# define ERR_NOUSER -1 +# define ERR_NOSHADOW -2 +# define ERR_NOPASS -3 +# define ERR_BADPASS -4 +# define ERR_NOCF -5 +# define ERR_NOMEM -6 +# define ERR_NOLISTEN -7 +# define ERR_SOCKET -8 +# define ERR_OPT -9 +# define ERR_BIND -10 +# define ERR_LISTEN -11 + +# define CT_NONE 0 +# define CT_LISTEN 1 +# define CT_CLIENT 2 +# define CT_CONFIG 3 + +# define MT_NONE 0 +# define MT_ERROR 1 +# define MT_MSG 2 + +typedef struct L_Struct { + char *IP; + struct L_Struct *next; +} LST; +# define LSTS sizeof(LST) + +typedef struct S_Struct { + char *IP; + struct S_Struct *next; +} SST; +# define SSTS sizeof(SST) + +typedef struct C_Struct { + char *IP; + struct C_Struct *next; +} CST; +# define CSTS sizeof(CST) + +typedef struct P_Struct { + char *IP; + struct P_Struct *next; +} PST; +# define PSTS sizeof(PST) + +typedef struct U_Struct { + char *uname; + struct U_Struct *next; +} UST; +# define USTS sizeof(UST) + +typedef struct N_Struct { + int type; + char *IP; + int sfd; + unsigned long timeout; + int loggedin; + char *uname; + struct N_Struct *next; +} NST; +# define NSTS sizeof(NST) + +# ifndef USERV_MAIN +extern LST *laddr; +extern CST *caddr; +extern UST *auser; +extern NST *nconn; +extern SST *saddr; +extern PST *paddr; +# endif + +#endif +