Makefile
aidepost
base64
+chkpwd
citadel
citadel.config
citadel.control
citmail
citserver
config.cache
+config.h.in
config.log
config.status
configure
userlist
weekly
whobbs
-config.h.in
+1999-04-03 Nathan Bryant <bryant@cs.usm.maine.edu>
+ * Makefile.in, configure.in, chkpwd.c, acconfig.h: support for
+ `chkpwd', a setuid helper program for machines which use shadow
+ passwords (configure --enable-chkpwd)
+ * Makefile.in, configure.in, auth.c, citadel.pam, user_ops.c: support
+ for PAM or shadow passwords (configure --with-pam)
+ * Makefile.in: made some messages simpler
+ * citadel.spec: updated for 5.53; correct name of tarball; build with
+ --enable-chkpwd and --with-pam; add defattr tags so rpm's can be
+ built by non-root user
+ * commands.c: cosmetic cleanup
+ * config.c: (security/paranoia) check permissions on citadel.config
+
Sun Mar 21 14:21:47 EST 1999 Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
* messages.c: cosmetic cleanups to message reading loop
########################################################################
TARGETS=@TARGETS@
+CHKPWD=@CHKPWD@
all: $(TARGETS)
SO=@SO@
CLIENT_TARGETS=citadel$(SUFFIX) whobbs$(SUFFIX)
-SERVER_TARGETS=citserver setup
+SERVER_TARGETS=citserver setup $(CHKPWD)
SERV_MODULES=modules/serv_chat$(SO) \
modules/serv_upgrade$(SO) modules/serv_expire$(SO)
UTIL_TARGETS=aidepost netmailer netproc netsetup msgform readlog rcit \
prefix=@prefix@
srcdir=@srcdir@
+AUTH=@AUTH@
DEFS=@DEFS@
CPPFLAGS=@CPPFLAGS@ -I.
CFLAGS=@CFLAGS@
SERVER_LDFLAGS=@SERVER_LDFLAGS@
PICFLAGS=@PICFLAGS@
CURSES=@CURSES@
+chkpwd_LIBS=@chkpwd_LIBS@
LIBOBJS=@LIBOBJS@
PTHREAD_DEFS=-D_REENTRANT
INSTALL=@INSTALL@
room_ops.c rooms.c routines.c routines2.c serv_chat.c \
serv_info.c serv_test.c serv_upgrade.c setup.c snprintf.c stats.c \
support.c sysdep.c tools.c user_ops.c userlist.c serv_expire.c \
- whobbs.c sendcommand.c mime_parser.c base64.c qpdecode.c getutline.c
+ whobbs.c sendcommand.c mime_parser.c base64.c qpdecode.c getutline.c \
+ auth.c chkpwd.c
DEP_FILES=$(SOURCES:.c=.d)
citserver: citserver.ro user_ops.ro support.ro room_ops.ro file_ops.ro \
msgbase.ro config.ro sysdep.ro locate_host.ro \
housekeeping.ro database.ro control.ro logging.ro \
- policy.ro dynloader.ro tools.ro mime_parser.ro $(LIBOBJS:.o=.ro)
+ policy.ro dynloader.ro tools.ro mime_parser.ro $(AUTH) $(LIBOBJS:.o=.ro)
$(CC) \
citserver.ro user_ops.ro room_ops.ro file_ops.ro support.ro \
msgbase.ro config.ro sysdep.ro locate_host.ro \
housekeeping.ro database.ro control.ro logging.ro \
policy.ro dynloader.ro tools.ro mime_parser.ro \
- $(LIBOBJS:.o=.ro)\
+ $(AUTH) $(LIBOBJS:.o=.ro)\
$(LDFLAGS) $(SERVER_LDFLAGS) $(LIBS) -o citserver
.c.ro:
setup: setup.o tools.o
$(CC) setup.o tools.o $(CURSES) $(LDFLAGS) -o setup
+chkpwd: chkpwd.o auth.o config.o
+ $(CC) chkpwd.o auth.o config.o $(LDFLAGS) -o chkpwd $(chkpwd_LIBS)
+
netsetup: netsetup.o config.o
$(CC) netsetup.o config.o $(LDFLAGS) -o netsetup
install: install-exec install-data install-doc
install-data:
- for i in help messages network/spoolin network/spoolout \
+ @for i in help messages network/spoolin network/spoolout \
network/systems; do \
- ./mkinstalldirs $(prefix)/$$i; \
+ ./mkinstalldirs $(root)$(prefix)/$$i; \
done
- for i in citadel.rc public_clients \
+ @for i in citadel.rc public_clients \
`find help messages network -type f | grep -v CVS`; do \
- $(INSTALL_DATA) $$i $(prefix)/$$i; \
+ $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
+ echo $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
done
+ @if test -d $(root)/etc/pam.d; then \
+ $(INSTALL_DATA) citadel.pam $(root)/etc/pam.d/citadel; \
+ echo $(INSTALL_DATA) citadel.pam $(root)/etc/pam.d/citadel; \
+ fi
install-doc:
- ./mkinstalldirs $(prefix)/techdoc
- for i in *.txt `find techdoc -type f | grep -v CVS`; do \
- $(INSTALL_DATA) $$i $(prefix)/$$i; \
+ @./mkinstalldirs $(root)$(prefix)/techdoc
+ @for i in *.txt `find techdoc -type f | grep -v CVS`; do \
+ $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
+ echo $(INSTALL_DATA) $$i $(root)$(prefix)/$$i; \
done
install-exec: all weekly
- for i in bio bitbucket files images info modules userpics; do \
- ./mkinstalldirs $(prefix)/$$i; \
+ @for i in bio bitbucket files images info modules userpics; do \
+ ./mkinstalldirs $(root)$(prefix)/$$i; \
done
- for i in $(CLIENT_TARGETS) $(SERVER_TARGETS) $(UTIL_TARGETS) \
+ @for i in $(CLIENT_TARGETS) $(SERVER_TARGETS) $(UTIL_TARGETS) \
$(PROXY_TARGETS) $(SERV_MODULES) utilsmenu weekly \
dnetsetup; do \
- test -f $$i && $(INSTALL) $$i $(prefix)/$$i; \
+ if test -f $$i; then \
+ $(INSTALL) $$i $(root)$(prefix)/$$i; \
+ echo $(INSTALL) $$i $(root)$(prefix)/$$i; \
+ fi \
done
+ @if test -f $(root)$(prefix)/chkpwd; then \
+ chmod u+s $(root)$(prefix)/chkpwd; \
+ echo chmod +s $(root)$(prefix)/chkpwd; \
+ fi
clean:
rm -f *.o *.ro *.mo
rm -f Makefile sysdep.h config.cache config.log config.status *.d weekly
.c.d:
- $(CC) -M $(CPPFLAGS) $< | sed -e 's!$*.o!$*.o $*.ro $*.mo $@!' > $@
- test -s $@ || rm -f $@
+ @echo Checking dependencies for $<
+ @$(CC) -M $(CPPFLAGS) $< | sed -e 's!$*.o!$*.o $*.ro $*.mo $@!' > $@
+ @test -s $@ || rm -f $@
Makefile: $(srcdir)/Makefile.in config.status
CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status
/* define this to enable the autologin feature */
#undef ENABLE_AUTOLOGIN
+/* define this to enable use of the chkpwd program (for shadow passwords) */
+#undef ENABLE_CHKPWD
+
/* define this if struct utmp has an ut_type member */
#undef HAVE_UT_TYPE
--- /dev/null
+/*
+ * auth.c -- system-level password checking for autologin
+ * by Nathan Bryant, March 1999
+ *
+ * $Id$
+ */
+
+#ifdef linux
+#define _XOPEN_SOURCE /* needed for crypt() */
+#define _XOPEN_SOURCE_EXTENDED /* needed for strdup() */
+#endif
+
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "auth.h"
+#include "sysdep.h"
+
+#ifdef HAVE_GETSPNAM
+#include <shadow.h>
+#endif
+
+#ifdef HAVE_PAM_START
+#include <security/pam_appl.h>
+
+/*
+ * struct appdata: passed to the conversation function
+ */
+
+struct appdata
+{
+ const char *name;
+ const char *pw;
+};
+
+/*
+ * conv(): the PAM conversation function. this assumes that a
+ * PAM_PROMPT_ECHO_ON is asking for a username, and a PAM_PROMPT_ECHO_OFF is
+ * asking for a password. esoteric authentication modules will fail with this
+ * code, but we can't really support them with the existing client protocol
+ * anyway. the failure mode should be to deny access, in any case.
+ */
+
+static int conv(int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr)
+{
+ struct pam_response *temp_resp;
+ struct appdata *data = appdata_ptr;
+
+ if ((temp_resp = malloc(sizeof(struct pam_response[num_msg]))) == NULL)
+ return PAM_CONV_ERR;
+
+ while (num_msg--)
+ {
+ switch ((*msg)[num_msg].msg_style)
+ {
+ case PAM_PROMPT_ECHO_ON:
+ temp_resp[num_msg].resp = strdup(data->name);
+ break;
+ case PAM_PROMPT_ECHO_OFF:
+ temp_resp[num_msg].resp = strdup(data->pw);
+ break;
+ default:
+ temp_resp[num_msg].resp = NULL;
+ }
+ temp_resp[num_msg].resp_retcode = 0;
+ }
+
+ *resp = temp_resp;
+ return PAM_SUCCESS;
+}
+#endif /* HAVE_PAM_START */
+
+/*
+ * validpw(): check that `pass' is the correct password for `uid'
+ * returns zero if no, nonzero if yes
+ */
+
+int validpw(uid_t uid, const char *pass)
+{
+#ifdef HAVE_PAM_START
+ struct pam_conv pc;
+ struct appdata data;
+ pam_handle_t *ph;
+ int i;
+#else
+ char *crypted_pwd;
+#ifdef HAVE_GETSPNAM
+ struct spwd *sp;
+#endif
+#endif
+ struct passwd *pw;
+ int retval = 0;
+
+ if ((pw = getpwuid(uid)) == NULL)
+ return retval;
+
+#ifdef HAVE_PAM_START
+ pc.conv = conv;
+ pc.appdata_ptr = &data;
+ data.name = pw->pw_name;
+ data.pw = pass;
+ if (pam_start("citadel", pw->pw_name, &pc, &ph) != PAM_SUCCESS)
+ return retval;
+
+ if ((i = pam_authenticate(ph, PAM_SILENT)) == PAM_SUCCESS)
+ if ((i = pam_acct_mgmt(ph, PAM_SILENT)) == PAM_SUCCESS)
+ retval = -1;
+
+ pam_end(ph, i | PAM_DATA_SILENT);
+#else
+ crypted_pwd = pw->pw_passwd;
+
+#ifdef HAVE_GETSPNAM
+ if ((sp = getspnam(pw->pw_name)) != NULL)
+ crypted_pwd = sp->sp_pwdp;
+#endif
+
+ if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd))
+ retval = -1;
+#endif /* HAVE_PAM_START */
+
+ return retval;
+}
--- /dev/null
+/* $Id$ */
+int validpw(uid_t uid, const char *pass);
--- /dev/null
+/*
+ * chkpwd.c: a setuid helper program for machines which use shadow passwords
+ * by Nathan Bryant, March 1999
+ *
+ * $Id$
+ */
+
+#include <pwd.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "auth.h"
+#include "config.h"
+#include "citadel.h"
+
+int main(void)
+{
+ uid_t uid;
+ struct passwd *pw;
+ char buf[256];
+
+ get_config();
+
+ if ((uid = getuid()) != BBSUID)
+ {
+ pw = getpwuid(uid);
+ openlog("chkpwd", LOG_CONS, LOG_AUTH);
+ syslog(LOG_WARNING, "invoked by %s (uid %u); possible breakin/probe "
+ "attempt", pw != NULL ? pw->pw_name : "?", uid);
+ return 1;
+ }
+
+ if (fgets(buf, sizeof buf, stdin) == NULL)
+ return 1;
+
+ strtok(buf, "\n");
+ uid = atoi(buf);
+
+ if (fgets(buf, sizeof buf, stdin) == NULL)
+ return 1;
+
+ strtok(buf, "\n");
+
+ if (validpw(uid, buf))
+ return 0;
+
+ return 1;
+}
--- /dev/null
+#%PAM-1.0
+#
+# /etc/pam.d/citadel: PAM configuration file for Linux-PAM.
+#
+# $Id$
+#
+auth required /lib/security/pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed
+auth required /lib/security/pam_pwdb.so shadow
+auth required /lib/security/pam_shells.so
+account required /lib/security/pam_pwdb.so
# $Id$
Summary: Citadel/UX
Name: citadel
-Version: 5.52
+Version: 5.53
Release: 1
Copyright: GPL
Group: Applications/Communications
-Source0: citadel.tar.gz
+Source0: citadel-ux-%{PACKAGE_VERSION}.tar.gz
Buildroot: /var/tmp/citadel-%{PACKAGE_VERSION}-root
Autoprov: false
%setup -n citadel
%build
-CFLAGS="$RPM_OPT_FLAGS" ./configure
+CFLAGS="$RPM_OPT_FLAGS" ./configure --enable-chkpwd --with-pam
make
%install
rm -rf $RPM_BUILD_ROOT
-mkdir -p $RPM_BUILD_ROOT/usr/local/citadel
-make prefix=$RPM_BUILD_ROOT/usr/local/citadel install
+mkdir -p $RPM_BUILD_ROOT/etc/pam.d
+make root=$RPM_BUILD_ROOT install
find $RPM_BUILD_ROOT/usr/local/citadel -type d | sed "s|$RPM_BUILD_ROOT|%dir |" > filelist
find $RPM_BUILD_ROOT -type f | egrep -v '(citadel\.rc|public_clients|/help/|/messages/|/network/)' | sed "s|$RPM_BUILD_ROOT||" >> filelist
find $RPM_BUILD_ROOT -type f | egrep '(citadel\.rc|public_clients|/help/|/messages/|/network/)' | sed "s|$RPM_BUILD_ROOT|%config |" >> filelist
rm -f filelist
%files -f filelist
+%defattr(-,root,root)
time_t start_time, now;
char inbuf[2];
+ fflush(stdout);
time(&start_time);
do {
*/
do {
do_keepalive();
- fflush(stdout);
FD_ZERO(&rfds);
FD_SET(0,&rfds);
tv.tv_sec = S_KEEPALIVE;
#include "sysdep.h"
#include <stdlib.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
void get_config(void) {
FILE *cfp;
+ struct stat st;
if (chdir( home_specified ? bbs_home_directory : BBSDIR ) != 0) {
fprintf(stderr, "Cannot start.\nThere is no Citadel installation in %s\n%s\n",
(home_specified ? bbs_home_directory : BBSDIR),
strerror(errno));
- exit(errno);
+ exit(1);
}
cfp=fopen("citadel.config","rb");
if (cfp==NULL) {
fprintf(stderr, "There is no citadel.config in %s\n%s\n",
(home_specified ? bbs_home_directory : BBSDIR),
strerror(errno));
- exit(errno);
+ exit(1);
}
fread((char *)&config,sizeof(struct config),1,cfp);
+ if (fstat(fileno(cfp), &st)) {
+ perror("citadel.config");
+ exit(1);
+ }
+ if (st.st_uid != BBSUID || st.st_mode != (S_IFREG | S_IRUSR | S_IWUSR))
+ {
+ fprintf(stderr, "check the permissions on citadel.config\n");
+ exit(1);
+ }
fclose(cfp);
if ( (config.c_setup_level / 10) != (REV_LEVEL/10) ) {
fprintf(stderr, "config: Your data files are out of date. ");
fi
AC_ARG_ENABLE(autologin, [ --disable-autologin disable autologin (default is enabled if possible)])
+AC_ARG_ENABLE(chkpwd, [ --enable-chkpwd build 'chkpwd' (use this if you have shadow passwords)])
+AC_ARG_WITH(pam, [ --with-pam use PAM if present])
dnl By default, we only build the client (citadel and whobbs) unless we can
dnl figure out how to build with POSIX threads.
SO=.mo
AC_DEFINE(HAVE_NONREENTRANT_NETDB)
;;
- dnl Digital Unix has an odd way to build pthreads, and we can't build
- dnl pthreads programs with gcc due to header problems.
+ dnl Digital Unix has an odd way to build for pthreads, and we can't
+ dnl build pthreads programs with gcc due to header problems.
alpha*-dec-osf*)
test -z "$CC" && CC=cc
SERVER_LDFLAGS=-pthread
dnl -lcrypt and -ldl, because some systems (like Irix) have both.
AC_CHECK_FUNCS(crypt dlopen)
-dnl We only need crypt() if we're using autologin. FIXME: implement shadow
-dnl passwords and/or PAM...
-if test "$enable_autologin" != no -a "$ac_cv_func_crypt" = no; then
- AC_CHECK_LIB(crypt, crypt)
-fi
-
-dnl Enable autologin if the feature is requested (which is the default) and
-dnl a crypt() functin is available.
-if test "$enable_autologin" != no -a \( "$ac_cv_func_crypt" = yes -o "$ac_cv_lib_crypt_crypt" = yes \); then
- AC_DEFINE(ENABLE_AUTOLOGIN)
+if test "$ac_cv_func_dlopen" = no; then
+ AC_CHECK_LIB(dl, dlopen, [LIBS="-ldl $LIBS"
+ chkpwd_LIBS=-ldl])
fi
-if test "$ac_cv_func_dlopen" = no; then
- AC_CHECK_LIB(dl, dlopen)
+dnl Determine the system's authentication capabilities, if autologin is
+dnl requested. We currently support PAM, standard getpwnam(), and getspnam()
+dnl (Linux shadow passwords)
+if test "$enable_autologin" != no; then
+ if test "$with_pam" = yes; then
+ save_LIBS=$LIBS
+ AC_CHECK_LIB(pam, pam_start, [chkpwd_LIBS="-lpam $chkpwd_LIBS"
+ LIBS="-lpam $LIBS"])
+ AC_CHECK_FUNCS(pam_start)
+ test "$enable_chkpwd" = yes && LIBS=$save_LIBS
+ fi
+ if test "$ac_cv_func_pam_start" = no -o "$with_pam" != yes; then
+ AC_CHECK_LIB(shadow, getspnam)
+ if test "$ac_cv_func_crypt" = no; then
+ AC_CHECK_LIB(crypt, crypt, [chkpwd_LIBS=-lcrypt
+ test "$enable_chkpwd" != yes && \
+ LIBS="-lcrypt $LIBS"])
+ fi
+ fi
+ if test "$ac_cv_func_crypt" = yes -o "$ac_cv_lib_crypt_crypt" = yes -o "$ac_cv_func_pam_start" = yes; then
+ AC_DEFINE(ENABLE_AUTOLOGIN)
+ if test "$enable_chkpwd" = yes; then
+ AC_DEFINE(ENABLE_CHKPWD)
+ CHKPWD=chkpwd
+ else
+ AUTH=auth.ro
+ fi
+ fi
fi
AC_CHECK_LIB(gdbm, gdbm_open)
AC_PROG_GCC_TRADITIONAL
AC_TYPE_SIGNAL
AC_FUNC_VPRINTF
-AC_CHECK_FUNCS(mkdir mkfifo mktime pthread_cancel rmdir select socket strerror)
+AC_CHECK_FUNCS(getspnam mkdir mkfifo mktime pthread_cancel rmdir select socket strerror)
AC_CHECK_FUNC(pthread_create, TARGETS="client server utils serv_modules")
AC_REPLACE_FUNCS(snprintf getutline)
dnl Done! Now write the Makefile and sysdep.h
+AC_SUBST(AUTH)
AC_SUBST(SO)
+AC_SUBST(CHKPWD)
AC_SUBST(CURSES)
+AC_SUBST(chkpwd_LIBS)
AC_SUBST(TARGETS)
AC_SUBST(SERVER_LDFLAGS)
AC_SUBST(PICFLAGS)
- Citadel/UX release 5.52
+ Citadel/UX release 5.53
Copyright (c) 1987-1999 by:
Art Cancro <ajc@uncnsrd.mt-kisco.ny.us>
-Portions (c) 1998 by:
+Portions (c) 1998-1999 by:
Brian Costello <btx@calyx.net>
Nathan Bryant <bryant@cs.usm.maine.edu>
/* $Id$ */
-#ifndef _SGI_SOURCE
-/* needed to properly enable crypt() stuff on some systems */
-#define _XOPEN_SOURCE
-/* needed for str[n]casecmp() on some systems if the above is defined */
-#define _XOPEN_SOURCE_EXTENDED
-/* needed to enable threads on some systems if the above are defined */
-#define _POSIX_C_SOURCE 199506L
-#endif
-
#include "sysdep.h"
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <pwd.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <sys/time.h>
#include <string.h>
#include <syslog.h>
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
+#ifndef ENABLE_CHKPWD
+#include "auth.h"
+#endif
#include "citadel.h"
#include "server.h"
#include "database.h"
PerformSessionHooks(EVT_LOGOUT);
}
+#ifdef ENABLE_CHKPWD
+/*
+ * an alternate version of validpw() which executes `chkpwd' instead of
+ * verifying the password directly
+ */
+static int validpw(uid_t uid, const char *pass)
+{
+ pid_t pid;
+ int status, pipev[2];
+ char buf[24];
+
+ if (pipe(pipev)) {
+ lprintf(1, "pipe failed (%s): denying autologin access for "
+ "uid %u\n", strerror(errno), uid);
+ return 0;
+ }
+
+ switch (pid = fork()) {
+ case -1:
+ lprintf(1, "fork failed (%s): denying autologin access for "
+ "uid %u\n", strerror(errno), uid);
+ close(pipev[0]);
+ close(pipev[1]);
+ return 0;
+
+ case 0:
+ close(pipev[1]);
+ if (dup2(pipev[0], 0) == -1) {
+ perror("dup2");
+ exit(1);
+ }
+ close(pipev[0]);
+
+ execl(BBSDIR "/chkpwd", BBSDIR "/chkpwd", NULL);
+ perror(BBSDIR "/chkpwd");
+ exit(1);
+ }
+
+ close(pipev[0]);
+ write(pipev[1], buf, sprintf(buf, "%u\n", uid));
+ write(pipev[1], pass, strlen(pass));
+ write(pipev[1], "\n", 1);
+ close(pipev[1]);
+
+ while (waitpid(pid, &status, 0) == -1)
+ if (errno != EINTR) {
+ lprintf(1, "waitpid failed (%s): denying autologin "
+ "access for uid %u\n",
+ strerror(errno), uid);
+ return 0;
+ }
+
+ if (WIFEXITED(status) && !WEXITSTATUS(status))
+ return 1;
+
+ return 0;
+ }
+#endif
void cmd_pass(char *buf)
{
char password[256];
int code;
- struct passwd *p;
extract(password,buf,0);
strproc(CC->usersupp.password);
code = strcasecmp(CC->usersupp.password,password);
}
- else {
- p = (struct passwd *)getpwuid(CC->usersupp.USuid);
#ifdef ENABLE_AUTOLOGIN
- if (p!=NULL) {
- if (!strcmp(p->pw_passwd,
- (char *)crypt(password,p->pw_passwd))) {
- code = 0;
- lgetuser(&CC->usersupp, CC->curr_user);
- strcpy(CC->usersupp.password, password);
- lputuser(&CC->usersupp, CC->curr_user);
- }
+ else {
+ if (validpw(CC->usersupp.USuid, password)) {
+ code = 0;
+ lgetuser(&CC->usersupp, CC->curr_user);
+ safestrncpy(CC->usersupp.password, password,
+ sizeof CC->usersupp.password);
+ lputuser(&CC->usersupp, CC->curr_user);
}
-#endif
}
+#endif
if (!code) {
(CC->logged_in) = 1;