commit d2f0741fd4814189838e344f03f995c892aeb107 Author: Gergely Polonkai Date: Wed Apr 27 20:35:44 2016 +0200 Initial 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 +