This commit is contained in:
Gergely Polonkai 2016-04-27 20:35:44 +02:00
commit d2f0741fd4
13 changed files with 1803 additions and 0 deletions

38
Makefile Normal file
View File

@ -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

77
PROTO Normal file
View File

@ -0,0 +1,77 @@
Lines beginning with "S:" are server messages.
Lines beginning with "C:" are client messages.
S: <listening on port 8778>
C: <connecting>
If the client is from an allowed IP:
S: R
Or else:
S: D
S: <close connection>
From now on, we assume that a connection is already built to the server
C: L <uname> <pass>
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: <close connection>
C: U <uid>
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 <uname>
If client hasn't login yet:
S: L
If uname exists:
S: U
If uname doesn't exist:
S: F
C: A <uname>:<uid>:<teacher?>:<samba?>:<passwd>:<comment>
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 <uname>
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

5
README Normal file
View File

@ -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.

189
common.c Normal file
View File

@ -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 <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <pwd.h>
#include <crypt.h>
#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;
}

48
context.c Normal file
View File

@ -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 <string.h>
# include <stdio.h>
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

251
data.c Normal file
View File

@ -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 <string.h>
#include <stdlib.h>
#include <unistd.h>
#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;
}

35
functions.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _US_FUNCTIONS_H
# define _US_FUNCTIONS_H
# include <sys/types.h>
# 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 */

63
logging.c Normal file
View File

@ -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 <syslog.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <time.h>
#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();
}

116
main.c Normal file
View File

@ -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 <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#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;
}

162
misc.c Normal file
View File

@ -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 <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <pwd.h>
#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;
}

645
networking.c Normal file
View File

@ -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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <crypt.h>
#include <sys/wait.h>
#include <stdarg.h>
#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))