]> code.citadel.org Git - citadel.git/blobdiff - citadel/user_ops.c
* Makefile.in, configure.in, chkpwd.c, acconfig.h: support for
[citadel.git] / citadel / user_ops.c
index bec8751edb44dc36975dc9b7b14edf978c1255d3..0848a52982d994cebe00f75bd449a4bf1e685278 100644 (file)
@@ -1,12 +1,6 @@
 /* $Id$ */
 
-/* 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
-
+#include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.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>
 #include <limits.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"
@@ -32,7 +32,7 @@
 #include "msgbase.h"
 #include "config.h"
 #include "dynloader.h"
-#include "sysdep.h"
+#include "tools.h"
 
 
 /*
@@ -45,10 +45,12 @@ int getuser(struct usersupp *usbuf, char name[]) {
        int a;
        struct cdbdata *cdbus;
 
-       bzero(usbuf, sizeof(struct usersupp));
+       memset(usbuf, 0, sizeof(struct usersupp));
        for (a=0; a<=strlen(name); ++a) {
-               lowercase_name[a] = tolower(name[a]);
+               if (a < sizeof(lowercase_name))
+                       lowercase_name[a] = tolower(name[a]);
                }
+       lowercase_name[sizeof(lowercase_name)-1] = 0;
 
        cdbus = cdb_fetch(CDB_USERSUPP, lowercase_name, strlen(lowercase_name));
        if (cdbus == NULL) {
@@ -87,8 +89,10 @@ void putuser(struct usersupp *usbuf, char *name)
        int a;
 
        for (a=0; a<=strlen(name); ++a) {
-               lowercase_name[a] = tolower(name[a]);
+               if (a < sizeof(lowercase_name))
+                       lowercase_name[a] = tolower(name[a]);
                }
+       lowercase_name[sizeof(lowercase_name)-1] = 0;
 
        cdb_store(CDB_USERSUPP,
                lowercase_name, strlen(lowercase_name),
@@ -174,7 +178,7 @@ void CtdlGetRelationship(struct visit *vbuf,
                rel_user->usernum);
 
        /* Clear out the buffer */
-       bzero(vbuf, sizeof(struct visit));
+       memset(vbuf, 0, sizeof(struct visit));
 
        cdbvisit = cdb_fetch(CDB_VISIT, IndexBuf, IndexLen);
        if (cdbvisit != NULL) {
@@ -225,7 +229,7 @@ int getuserbynumber(struct usersupp *usbuf, long int number)
        cdb_rewind(CDB_USERSUPP);
 
        while(cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
-               bzero(usbuf, sizeof(struct usersupp));
+               memset(usbuf, 0, sizeof(struct usersupp));
                memcpy(usbuf, cdbus->ptr,
                        ( (cdbus->len > sizeof(struct usersupp)) ?
                        sizeof(struct usersupp) : cdbus->len) );
@@ -299,7 +303,6 @@ void session_startup(void) {
        CC->fake_postname[0] = '\0';
        CC->fake_hostname[0] = '\0';
        CC->fake_roomname[0] = '\0';
-       CC->last_pager[0] = '\0';
        time(&CC->usersupp.lastcall);
 
        /* If this user's name is the name of the system administrator
@@ -340,12 +343,69 @@ void logout(struct CitContext *who)
        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);
 
@@ -368,20 +428,17 @@ void cmd_pass(char *buf)
                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;
@@ -775,6 +832,7 @@ void cmd_forg(void) {
        CtdlGetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
 
        vbuf.v_flags = vbuf.v_flags | V_FORGET;
+       vbuf.v_flags = vbuf.v_flags & ~V_ACCESS;
 
        CtdlSetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
        lputuser(&CC->usersupp,CC->curr_user);
@@ -810,7 +868,7 @@ void cmd_gnur(void) {
         */
        cdb_rewind(CDB_USERSUPP);
        while (cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
-               bzero(&usbuf, sizeof(struct usersupp));
+               memset(&usbuf, 0, sizeof(struct usersupp));
                memcpy(&usbuf, cdbus->ptr,
                        ( (cdbus->len > sizeof(struct usersupp)) ?
                        sizeof(struct usersupp) : cdbus->len) );
@@ -954,7 +1012,7 @@ void ForEachUser(void (*CallBack)(struct usersupp *EachUser)) {
        cdb_rewind(CDB_USERSUPP);
 
        while(cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
-               bzero(&usbuf, sizeof(struct usersupp));
+               memset(&usbuf, 0, sizeof(struct usersupp));
                memcpy(&usbuf, cdbus->ptr,
                        ( (cdbus->len > sizeof(struct usersupp)) ?
                        sizeof(struct usersupp) : cdbus->len) );
@@ -1078,7 +1136,6 @@ void cmd_regi(void) {
        CitControl.MMflags = CitControl.MMflags | MM_VALID ;
        put_control();
        end_critical_section(S_CONTROL);
-       cprintf("%d *** End of registration.\n",OK);
        }