646 lines
21 KiB
C
646 lines
21 KiB
C
/*
|
|
* 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))
|
|
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;
|
|
}
|
|
|