The SSH host key has changed on 8 April, 2022 to this one: SHA256:573uTBSeh74kvOo0HJXi5ijdzRm8me27suzNEDlGyrQ
Browse Source

Initial

master
Gergely Polonkai 6 years ago
commit
d2f0741fd4
  1. 38
      Makefile
  2. 77
      PROTO
  3. 5
      README
  4. 189
      common.c
  5. 48
      context.c
  6. 251
      data.c
  7. 35
      functions.h
  8. 63
      logging.c
  9. 116
      main.c
  10. 162
      misc.c
  11. 645
      networking.c
  12. 88
      signal.c
  13. 86
      userv.h

38
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

77
PROTO

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

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

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

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

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

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

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

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

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

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