Back to beaubozarth.com
server.c
/*
* Authentication Server file
* copyright beaubozarth.com 2008
*/
#include "includes.h"
static int DAEMON_MAX = 5;
/*
* the last message the was processed
*/
int last_msg = -1;
int proc_max = 0;
const char *listen_port = "135";
/*
* a useful macro to debug the last message processed
*/
#define LAST_MESSAGE() cifs_function( last_msg )
extern pstring usr_socket_opts;
extern SIG_ATOMIC_T sigterm;
extern SIG_ATOMIC_T sighup;
static int server_fd = -1;
int daemon_fd(void)
{
return server_fd;
}
static void daemon_fd_set(int fd)
{
server_fd = fd;
client_setfd(fd);
}
/*
* Signal termination.
*/
static void sig_term(void)
{
sigterm = 1;
sys_sel_signal();
}
/*
* Process a sighup.
*/
static void sig_hup(int sig)
{
sighup = 1;
sys_sel_signal();
}
/*
* SAM sync message
*/
static void SAM_sync_msg(int UNUSED(msg_type), pid_t UNUSED(pid),
void
*UNUSED(buf), size_t UNUSED(len))
{
DEBUG( 10, ("** sam sync
message received, ignoring\n"));
}
/*
* SAM sync replicate message
*/
static void SAM_replicate_msg( int msg_type, pid_t pid, void *buf,
size_t len )
{
uint32 lserial;
if (len != sizeof( uint32))
return;
lserial = *((uint32 *) buf);
DEBUG( 3,
("SAM_replicate_message: received msg, serial = 0x%04x\n",
lserial));
}
/*
* Begin socket connection
*/
static BOOL socket_open(void)
{
/*
* close standard file
descriptors
*/
daemon_fd_set(dup(0));
/*
* Don't close stderr.
*/
close_fds(FALSE);
set_socket_opts(daemon_fd(), "SO_KEEPALIVE");
set_socket_opts(daemon_fd(), usr_socket_opts);
return TRUE;
}
static void msg_exit_server(int msg_type, pid_t src, void *buf, size_t
len)
{
exit_server("Got a exit");
}
/*
* Have we maxed the process limit ?
*/
static BOOL max_daemon_proc(void)
{
if (proc_max <= DAEMON_MAX)
proc_max++;
return TRUE;
else
{
if (debug)
{
DEBUG(
0,("max_daemon_proc: can't start daemon, maxed out.\n"));
}
}
return FALSE;
}
/*
* Open a socket.
*/
static BOOL open_socket(BOOL daemonize, BOOL nodaemon)
{
int num_if = iface_count();
int num_sockets = 0;
int lset_fd[FD_SETSIZE];
fd_set l_set;
int s;
int i;
if (!daemonize)
{
return socket_open();
}
/*
* Kill the zombies
*/
signalcatch(SIGCLD, sigcld);
FD_ZERO(&l_set);
/*
* Default port 135
*/
s = lset_fd[num_sockets] =
open_socket_in(SOCK_STREAM,
listen_port, 0,
ifip->s_addr,
TRUE);
if (s == -1)
return FALSE;
/*
* start listening
*/
set_socket_opts(s,"SO_KEEPALIVE");
set_socket_opts(s,usr_socket_opts);
/*
* Set daemon socket
non-blocking for the accept.
*/
set_blocking(s,FALSE);
if (listen(s, LISTEN_BACKLOG ) == -1)
{
DEBUG(0, ("listen: %s\n",
strerror( errno)));
close(s);
return FALSE;
}
FD_SET(s, &l_set);
num_sockets++;
if (num_sockets >= FD_SETSIZE)
{
DEBUG(0, ("open_socket: Too many
sockets to bind to\n"));
return FALSE;
}
else
{
/*
* Just bind to 0.0.0.0 -
accept all connections
*/
fstring tok;
const char *ptr;
num_if = 1;
/*
* open a socket
*/
s = open_socket_in(SOCK_STREAM,
listen_port, 0,
interpret_addr(lp_socket_address()),
TRUE);
if (s == -1)
return(FALSE);
/*
* listen
*/
set_socket_opts(s,
"SO_KEEPALIVE");
set_socket_opts(s,
user_socket_options);
/*
* Set socket to non-blocking
*/
set_blocking(s, FALSE);
if (listen( s, LISTEN_BACKLOG )
== -1)
{
DEBUG(0,
("open_socket: listen: %s\n",
strerror( errno)));
close(s);
return FALSE;
}
lset_fd[num_sockets] = s;
FD_SET(s, &l_set);
num_sockets++;
if (num_sockets >= FD_SETSIZE)
{
DEBUG(0, (
"open_socket: Too many sockets to bind to\n"));
return FALSE;
}
}
SAFE_FREE(listen_port);
/*
* messages
*/
reg_msg(MSG_SAM_SYNC,
SAM_sync_msg);
reg_msg(MSG_SAM_REPL,
SAM_replicate_msg);
reg_msg(MSG_SHUTDOWN,
msg_exit_server);
/*
* accept incoming connections
* fork each new process
*/
DEBUG(2, ("listening for a connection\n"));
while (1)
{
fd_set lfds;
int num;
/*
* Free temp memory from the
parent.
*/
talloc_free();
/*
* respond to PING and DEBUG
messages from the parent.
*/
dispatch_msg();
memcpy( (char * ) &lfds,
(char * )
&l_set,
sizeof( l_set));
num = sys_select(FD_SETSIZE,
&lfds,
NULL,
NULL,
NULL);
if (num == -1 && errno ==
EINTR)
{
if (sigterm)
{
exit_server("Caught SIGTERM");
}
/*
* check for
sighup
*/
if (sighup)
{
DEBUG(1, ("Reloading services after SIGHUP\n"));
services_reload(FALSE);
sighup = 0;
}
continue;
}
/*
* check for need to reload
services
*/
check_reload(time(NULL));
/*
* accept on read-only sockets.
*/
for( ; num > 0; num--)
{
struct
sockaddr addr;
socklen_t
in_addrlen = sizeof(addr);
s = -1;
for(i = 0; i
< num_sockets; i++)
{
if(FD_ISSET(lset_fd[i], &lfds))
{
s = lset_fd[i];
/*
* Clear this it's done.
*/
FD_CLR(lset_fd[i], &lfds);
break;
}
}
daemon_fd_set(accept( s, &addr, &in_addrlen));
if
(daemon_fd() == -1 && errno == EINTR)
continue;
if
(daemon_fd() == -1)
{
DEBUG(0, ("open_socket: accept: %s\n",
strerror(errno)));
continue;
}
/*
* Ensure the
child is in blocking mode
*/
set_blocking(daemon_fd(), TRUE);
if
(daemon_fd() != -1 && nodaemon)
return TRUE;
if
(max_daemon_proc() && daemon_fd() != -1 &&
sys_fork()==0)
{
/*
* We are now the child
* close any listening sockets
*/
for(i = 0; i < num_sockets; i++)
close(lset_fd[i]);
/*
* close the file descriptors
*/
close_fds(FALSE);
set_socket_opts(daemon_fd(), "SO_KEEPALIVE");
set_socket_opts(daemon_fd(), usr_socket_opts);
set_remote_machine_name(get_peer_addr( daemon_fd()),
FALSE);
/*
* Reset the random number generator
* keeps children from getting the
* same random numbers.
*/
flag_random_reseed();
return TRUE;
}
/*
* Parent
doesn't need this
*/
close(daemon_fd());
daemon_fd_set(-1);
}
} /* end while loop */
/*
* NOTREACHED
*/
}
/*
* Reload services file.
*/
BOOL services_reload(BOOL test)
{
BOOL ret;
reopen_logs();
if (daemon_fd() != -1)
{
set_socket_opts(daemon_fd(),
"SO_KEEPALIVE");
set_socket_opts(daemon_fd(),
usr_socket_opts);
}
/*
* flush service parameters
*/
set_current_service(NULL, 0, TRUE);
return(ret);
}
/*
* The server's done, stick a fork in it
*/
void exit_server(const char *reason)
{
static int firsttime = 1;
extern char *last_inbuf;
extern struct auth_context
*negprot_global_auth_context;
if (!firsttime)
exit(0);
firsttime = 0;
DEBUG( 2,("Closing connections\n"));
if (negprot_global_auth_context)
{
(negprot_global_auth_context->free ) (
&negprot_global_auth_context);
}
conn_close_all();
invalidate_all_vuids();
print_notify_send_messages(3);
/*
* Handle exit events
*/
do_exit_events();
/*
* delete the connections.
*/
conn_give(NULL, "");
resp_rem_msg();
dec_proc_cnt();
if (!reason)
{
int oldlevel = DEBUGLEVEL;
DEBUGLEVEL = 10;
DEBUG( 0, ("Last message was
%s\n",fn_name( last_msg)));
if (last_inbuf)
show_msg(last_inbuf);
DEBUGLEVEL = oldlevel;
}
locking_end();
DEBUG(3, ("Server exit (%s)\n", (reason ? reason :
"")));
exit(0);
}
/*
* Init the connect, service and file structs.
*/
static BOOL init_structs(void)
{
/*
* Set the machine NETBIOS name if not already
* set from the config file.
*/
if (!init_names())
return FALSE;
conn_init();
file_init();
/*
* RPC pipes
*/
init_rpc_pipe_hnd();
init_dptrs();
secrets_init();
return TRUE;
}
/*
* main
*/
int main(int argc, const char *argv[])
{
/*
* daemon or not
*/
static BOOL daemonize = FALSE;
static BOOL nodaemon = FALSE;
static BOOL fork = TRUE;
static BOOL to_stdout = FALSE;
static char *port = NULL;
int opt;
/*
* Set UID/GID to ensure we're root.
*/
uid = getuid();
if (uid != 0)
setuid(0, 0, 0);
gid = getegid();
if (gid != 0)
setgid(0, 0, 0);
/*
* Parse the args here
*/
while( (opt = getopt(argc, argv, "i:d:")) !=EOF)
{
switch(opt)
{
case 'i':
nodaemon =
TRUE;
break;
case 'd':
DEBUG = TRUE;
break;
default:
break;
}
}
if (nodaemon)
{
fork = FALSE;
to_stdout = TRUE;
}
if (to_stdout && fork)
{
DEBUG(0, ("DAEMON: Can't log to
stdout unless daemon is nodaemon (-i)\n"));
exit(-1);
}
start_log(to_stdout);
setup_sigfault( (void (*) (void *)) exit_server);
signalcatch(SIGTERM, SIGNAL_CAST sigterm);
signalcatch(SIGHUP, SIGNAL_CAST sighup);
/*
* Let's block some boring signals
*/
signalblock(TRUE, SIGPIPE);
signalblock(TRUE, SIGFPE);
signalblock(TRUE, SIGUSR2);
/* In POSIX signals are inherited. If the following
signals
* are masked, we'll die as we won't recieve them.
*/
signalblock(FALSE, SIGHUP);
signalblock(FALSE, SIGUSR1);
signalblock(FALSE, SIGTERM);
/*
* Set total control on permissions
*/
umask(0);
/*
* Re-open the log file if it's closed
* for some reason.
*/
reopen_log();
/*
* The following displays upon daemon startup
*/
DEBUG(0, ("tc auth server started.\n"));
DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n",
(int) getuid(), (int) getgid(),
(int) geteuid(),(int)
getegid()));
if (!daemonize && !socket_yes(0))
{
if (!nodaemon)
DEBUG(0,
("DAEMON: not a socket, assuming -d option\n"));
/*
* By setting daemonize
open_socket() doesn't
* get called later.
*/
daemonize = TRUE;
}
if (daemonize && !nodaemon)
{
DEBUG(3, ("fork the daemon.\n"));
fork_daemon(fork);
}
/*
* Set process group for signal management.
*/
if (nodaemon)
setpgid((pid_t) 0, (pid_t) 0);
if (daemonize)
pidfile_create("authserv");
/*
* Setup the tdb's
*/
if (!msg_init())
exit(1);
if (!sess_init())
exit(1);
if (conn_init() == NULL)
exit(1);
if (!lock_init(0))
exit(1);
if (!info_db_init())
exit(1);
if (!init_reg())
exit(1);
/*
* Setup so we can get messages.
*/
conn_entry();
if (!open_socket( daemonize, nodaemon))
exit(1);
/*
* after the fork()
*/
/*
* Try to set up a SID using PAM
*/
if(!passdb_init( FALSE))
exit(1);
if(!gsam_sid_get())
{
DEBUG(0, ("DAEMON: cannot create
SAM SID.\n"));
exit(1);
}
mod_init();
/*
* reload the services file.
*/
services_reload(TRUE);
if (!acct_policy_init())
{
DEBUG(0, ("Could not open account
policy tdb.\n"));
exit(1);
}
/*
* Setup oplocks
*/
if (!oplock_init())
exit(1);
/*
* Setup change notify
*/
if (!nchange_init())
exit(1);
/*
* re-init timezone
*/
init_time();
/*
* register msg handlers
*/
reg_msg(MSG_FORCE_TDIS, msg_force_tdis);
/*
* Process client requests here
*/
serv_process();
exit_server("normal exit");
return(0);
}