]> code.citadel.org Git - citadel.git/blobdiff - citadel/user_ops.c
* Added a separate authentication mode AUTHMODE_LDAP_AD for Active Directory's nonsta...
[citadel.git] / citadel / user_ops.c
index b78e8a3e9eb75ae52e8ec13dcbf8996cd4a341f9..bb803982af93da8fb8a1c23d4187079eeb86483d 100644 (file)
@@ -50,6 +50,7 @@
 #include "citadel_dirs.h"
 #include "genstamp.h"
 #include "threads.h"
+#include "citadel_ldap.h"
 
 /* These pipes are used to talk to the chkpwd daemon, which is forked during startup */
 int chkpwd_write_pipe[2];
@@ -196,6 +197,9 @@ int rename_user(char *oldname, char *newname) {
                                cdb_delete(CDB_USERS, oldnamekey, strlen(oldnamekey));
                                safestrncpy(usbuf.fullname, newname, sizeof usbuf.fullname);
                                putuser(&usbuf);
+                               cdb_store(CDB_USERSBYNUMBER, &usbuf.usernum, sizeof(long),
+                                       usbuf.fullname, strlen(usbuf.fullname)+1 );
+
                                retcode = RENAMEUSER_OK;
                        }
                }
@@ -355,33 +359,83 @@ int is_room_aide(void)
 }
 
 /*
- * getuserbynumber()  -  get user by number
- *                    returns 0 if user was found
+ * getuserbynumber() - get user by number
+ *                     returns 0 if user was found
  *
- * WARNING: don't use this function unless you absolutely have to.  It does
- *       a sequential search and therefore is computationally expensive.
+ * Note: fetching a user this way requires one additional database operation.
  */
-int getuserbynumber(struct ctdluser *usbuf, long int number)
+int getuserbynumber(struct ctdluser *usbuf, long number)
 {
-       struct cdbdata *cdbus;
+       struct cdbdata *cdbun;
+       int r;
 
-       cdb_rewind(CDB_USERS);
+       cdbun = cdb_fetch(CDB_USERSBYNUMBER, &number, sizeof(long));
+       if (cdbun == NULL) {
+               CtdlLogPrintf(CTDL_INFO, "User %ld not found\n", number);
+               return(-1);
+       }
 
-       while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) {
-               memset(usbuf, 0, sizeof(struct ctdluser));
-               memcpy(usbuf, cdbus->ptr,
-                      ((cdbus->len > sizeof(struct ctdluser)) ?
-                       sizeof(struct ctdluser) : cdbus->len));
-               cdb_free(cdbus);
-               if (usbuf->usernum == number) {
-                       cdb_close_cursor(CDB_USERS);
-                       return (0);
-               }
+       CtdlLogPrintf(CTDL_INFO, "User %ld maps to %s\n", number, cdbun->ptr);
+       r = getuser(usbuf, cdbun->ptr);
+       cdb_free(cdbun);
+       return(r);
+}
+
+
+
+/*
+ * Helper function for rebuild_usersbynumber()
+ */
+void rebuild_ubn_for_user(struct ctdluser *usbuf, void *data) {
+
+       struct ubnlist {
+               struct ubnlist *next;
+               char username[USERNAME_SIZE];
+               long usernum;
+       };
+
+       static struct ubnlist *u = NULL;
+       struct ubnlist *ptr = NULL;
+
+       /* Lazy programming here.  Call this function as a ForEachUser backend
+        * in order to queue up the room names, or call it with a null user
+        * to make it do the processing.
+        */
+       if (usbuf != NULL) {
+               ptr = (struct ubnlist *) malloc(sizeof (struct ubnlist));
+               if (ptr == NULL) return;
+
+               ptr->usernum = usbuf->usernum;
+               safestrncpy(ptr->username, usbuf->fullname, sizeof ptr->username);
+               ptr->next = u;
+               u = ptr;
+               return;
+       }
+
+       while (u != NULL) {
+               CtdlLogPrintf(CTDL_DEBUG, "Rebuilding usersbynumber index %10ld : %s\n",
+                       u->usernum, u->username);
+               cdb_store(CDB_USERSBYNUMBER, &u->usernum, sizeof(long), u->username, strlen(u->username)+1);
+
+               ptr = u;
+               u = u->next;
+               free(ptr);
        }
-       return (-1);
 }
 
 
+
+/*
+ * Rebuild the users-by-number index
+ */
+void rebuild_usersbynumber(void) {
+       cdb_trunc(CDB_USERSBYNUMBER);                   /* delete the old indices */
+       ForEachUser(rebuild_ubn_for_user, NULL);        /* enumerate the users */
+       rebuild_ubn_for_user(NULL, NULL);               /* and index them */
+}
+
+
+
 /*
  * getuserbyuid()  -     get user by system uid (for PAM mode authentication)
  *                    returns 0 if user was found
@@ -488,6 +542,34 @@ int CtdlLoginExistingUser(char *authname, char *trythisname)
 
        }
 
+#ifdef HAVE_LDAP
+       else if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
+       
+               /* LDAP auth mode */
+
+               uid_t ldap_uid;
+               char ldap_cn[256];
+               char ldap_dn[256];
+
+               found_user = CtdlTryUserLDAP(username, ldap_dn, sizeof ldap_dn, ldap_cn, sizeof ldap_cn, &ldap_uid);
+               if (found_user != 0) {
+                       return login_not_found;
+               }
+
+               found_user = getuserbyuid(&CC->user, ldap_uid);
+               if (found_user != 0) {
+                       create_user(trythisname, 0);
+                       found_user = getuserbyuid(&CC->user, ldap_uid);
+               }
+
+               if (found_user == 0) {
+                       if (CC->ldap_dn != NULL) free(CC->ldap_dn);
+                       CC->ldap_dn = strdup(ldap_dn);
+               }
+
+       }
+#endif
+
        else {
                /* native auth mode */
 
@@ -565,8 +647,9 @@ void cmd_user(char *cmdbuf)
 /*
  * session startup code which is common to both cmd_pass() and cmd_newu()
  */
-void session_startup(void)
+void do_login(void)
 {
+       CC->logged_in = 1;
        CtdlLogPrintf(CTDL_NOTICE, "<%s> logged in\n", CC->curr_user);
 
        lgetuser(&CC->user, CC->curr_user);
@@ -674,9 +757,7 @@ void logout(void)
                purge_user(CCC->user.fullname);
 
        /* Free any output buffers */
-       if (CCC->output_buffer != NULL) {
-               unbuffer_output();
-       }
+       unbuffer_output();
 }
 
 /*
@@ -753,13 +834,6 @@ void start_chkpwd_daemon(void) {
 }
 
 
-void do_login()
-{
-       (CC->logged_in) = 1;
-       session_startup();
-}
-
-
 int CtdlTryPassword(char *password)
 {
        int code;
@@ -815,6 +889,20 @@ int CtdlTryPassword(char *password)
                }
        }
 
+#ifdef HAVE_LDAP
+       else if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
+
+               /* LDAP auth mode */
+
+               if ((CC->ldap_dn) && (!CtdlTryPasswordLDAP(CC->ldap_dn, password))) {
+                       code = 0;
+               }
+               else {
+                       code = (-1);
+               }
+       }
+#endif
+
        else {
 
                /* native auth mode */
@@ -911,6 +999,9 @@ int purge_user(char pname[])
        /* delete any existing user/room relationships */
        cdb_delete(CDB_VISIT, &usbuf.usernum, sizeof(long));
 
+       /* delete the users-by-number index record */
+       cdb_delete(CDB_USERSBYNUMBER, &usbuf.usernum, sizeof(long));
+
        /* delete the userlog entry */
        cdb_delete(CDB_USERS, usernamekey, strlen(usernamekey));
 
@@ -934,6 +1025,40 @@ int purge_user(char pname[])
 }
 
 
+int internal_create_user (char *username, struct ctdluser *usbuf, uid_t uid)
+{
+       if (!getuser(usbuf, username)) {
+               return (ERROR + ALREADY_EXISTS);
+       }
+
+       /* Go ahead and initialize a new user record */
+       memset(usbuf, 0, sizeof(struct ctdluser));
+       safestrncpy(usbuf->fullname, username, sizeof usbuf->fullname);
+       strcpy(usbuf->password, "");
+       usbuf->uid = uid;
+
+       /* These are the default flags on new accounts */
+       usbuf->flags = US_LASTOLD | US_DISAPPEAR | US_PAGINATOR | US_FLOORS;
+
+       usbuf->timescalled = 0;
+       usbuf->posted = 0;
+       usbuf->axlevel = config.c_initax;
+       usbuf->USscreenwidth = 80;
+       usbuf->USscreenheight = 24;
+       usbuf->lastcall = time(NULL);
+
+       /* fetch a new user number */
+       usbuf->usernum = get_new_user_number();
+
+       /* add user to the database */
+       putuser(usbuf);
+       cdb_store(CDB_USERSBYNUMBER, &usbuf->usernum, sizeof(long), usbuf->fullname, strlen(usbuf->fullname)+1);
+
+       return 0;
+}
+
+
+
 /*
  * create_user()  -  back end processing to create a new user
  *
@@ -948,11 +1073,14 @@ int create_user(char *newusername, int become_user)
        char username[256];
        char mailboxname[ROOMNAMELEN];
        char buf[SIZ];
+       int retval;
        uid_t uid = (-1);
+       
 
        safestrncpy(username, newusername, sizeof username);
        strproc(username);
 
+       
        if (config.c_auth_mode == AUTHMODE_HOST) {
 
                /* host auth mode */
@@ -975,14 +1103,7 @@ int create_user(char *newusername, int become_user)
                        uid = pd.pw_uid;
                        if (IsEmptyStr (username))
                        {
-                               CtdlLogPrintf (CTDL_EMERG, 
-                                        "Can't find Realname for user %s [%d] in the Host Auth Database; giving up.\n", 
-                                        newusername, pd.pw_uid);
-                               snprintf(buf, SIZ, 
-                                        "Can't find Realname for user %s [%d] in the Host Auth Database; giving up.\n",
-                                        newusername, pd.pw_uid);
-                               aide_message(buf, "User Creation Failure Notice");
-
+                               safestrncpy(username, pd.pw_name, sizeof username);
                        }
                }
                else {
@@ -990,37 +1111,17 @@ int create_user(char *newusername, int become_user)
                }
        }
 
-       if (!getuser(&usbuf, username)) {
-               return (ERROR + ALREADY_EXISTS);
-       }
-
-       /* Go ahead and initialize a new user record */
-       memset(&usbuf, 0, sizeof(struct ctdluser));
-       safestrncpy(usbuf.fullname, username, sizeof usbuf.fullname);
-       strcpy(usbuf.password, "");
-       usbuf.uid = uid;
-
-       /* These are the default flags on new accounts */
-       usbuf.flags = US_LASTOLD | US_DISAPPEAR | US_PAGINATOR | US_FLOORS;
-
-       usbuf.timescalled = 0;
-       usbuf.posted = 0;
-       usbuf.axlevel = config.c_initax;
-       usbuf.USscreenwidth = 80;
-       usbuf.USscreenheight = 24;
-       usbuf.lastcall = time(NULL);
-
-       /* fetch a new user number */
-       usbuf.usernum = get_new_user_number();
-
-       /* The very first user created on the system will always be an Aide */
-       if (usbuf.usernum == 1L) {
-               usbuf.axlevel = 6;
+#ifdef HAVE_LDAP
+       if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
+               if (CtdlTryUserLDAP(username, NULL, 0, username, sizeof username, &uid) != 0) {
+                       return(ERROR + NO_SUCH_USER);
+               }
        }
-
-       /* add user to userlog */
-       putuser(&usbuf);
-
+#endif /* HAVE_LDAP */
+       
+       if ((retval = internal_create_user(username, &usbuf, uid)) != 0)
+               return retval;
+       
        /*
         * Give the user a private mailbox and a configuration room.
         * Make the latter an invisible system room.
@@ -1046,7 +1147,7 @@ int create_user(char *newusername, int become_user)
                /* Now become the user we just created */
                memcpy(&CC->user, &usbuf, sizeof(struct ctdluser));
                safestrncpy(CC->curr_user, username, sizeof CC->curr_user);
-               CC->logged_in = 1;
+               do_login();
        
                /* Check to make sure we're still who we think we are */
                if (getuser(&CC->user, CC->curr_user)) {
@@ -1067,7 +1168,6 @@ int create_user(char *newusername, int become_user)
 
 
 
-
 /*
  * cmd_newu()  -  create a new user account and log in as that user
  */
@@ -1116,7 +1216,6 @@ void cmd_newu(char *cmdbuf)
        a = create_user(username, 1);
 
        if (a == 0) {
-               session_startup();
                logged_in_response();
        } else if (a == ERROR + ALREADY_EXISTS) {
                cprintf("%d '%s' already exists.\n",
@@ -1132,12 +1231,26 @@ void cmd_newu(char *cmdbuf)
 }
 
 
+/*
+ * set password - back end api code
+ */
+void CtdlSetPassword(char *new_pw)
+{
+       lgetuser(&CC->user, CC->curr_user);
+       safestrncpy(CC->user.password, new_pw, sizeof(CC->user.password));
+       lputuser(&CC->user);
+       CtdlLogPrintf(CTDL_INFO, "Password changed for user <%s>\n", CC->curr_user);
+       PerformSessionHooks(EVT_SETPASS);
+}
+
 
 /*
- * set password
+ * set password - citadel protocol implementation
  */
 void cmd_setp(char *new_pw)
 {
+       int generate_random_password = 0;
+
        if (CtdlAccessCheck(ac_logged_in)) {
                return;
        }
@@ -1150,17 +1263,23 @@ void cmd_setp(char *new_pw)
                        ERROR + NOT_HERE);
                return;
        }
-       strproc(new_pw);
-       if (IsEmptyStr(new_pw)) {
-               cprintf("%d Password unchanged.\n", CIT_OK);
-               return;
+
+       if (!strcasecmp(new_pw, "GENERATE_RANDOM_PASSWORD")) {
+               char random_password[17];
+               generate_random_password = 1;
+               snprintf(random_password, sizeof random_password, "%08lx%08lx", random(), random());
+               CtdlSetPassword(random_password);
+               cprintf("%d %s\n", CIT_OK, random_password);
+       }
+       else {
+               strproc(new_pw);
+               if (IsEmptyStr(new_pw)) {
+                       cprintf("%d Password unchanged.\n", CIT_OK);
+                       return;
+               }
+               CtdlSetPassword(new_pw);
+               cprintf("%d Password changed.\n", CIT_OK);
        }
-       lgetuser(&CC->user, CC->curr_user);
-       safestrncpy(CC->user.password, new_pw, sizeof(CC->user.password));
-       lputuser(&CC->user);
-       cprintf("%d Password changed.\n", CIT_OK);
-       CtdlLogPrintf(CTDL_INFO, "Password changed for user <%s>\n", CC->curr_user);
-       PerformSessionHooks(EVT_SETPASS);
 }
 
 
@@ -1578,16 +1697,13 @@ void ListThisUser(struct ctdluser *usbuf, void *data)
                if ((CC->user.axlevel >= 6)
                    || ((usbuf->flags & US_UNLISTED) == 0)
                    || ((CC->internal_pgm))) {
-                       cprintf("%s|%d|%ld|%ld|%ld|%ld|",
+                       cprintf("%s|%d|%ld|%ld|%ld|%ld||\n",
                                usbuf->fullname,
                                usbuf->axlevel,
                                usbuf->usernum,
                                (long)usbuf->lastcall,
                                usbuf->timescalled,
                                usbuf->posted);
-                       if (CC->user.axlevel >= 6)
-                               cprintf("%s", usbuf->password);
-                       cprintf("\n");
                }
        }
 }