Back to index

citadel  8.12
user_ops.c
Go to the documentation of this file.
00001 /* 
00002  * Server functions which perform operations on user objects.
00003  *
00004  * Copyright (c) 1987-2011 by the citadel.org team
00005  *
00006  * This program is open source software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License as published
00008  * by the Free Software Foundation; either version 3 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00019  */
00020 
00021 #include "sysdep.h"
00022 #include <errno.h>
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <stdio.h>
00026 #include <fcntl.h>
00027 #include <signal.h>
00028 #include <pwd.h>
00029 #include <ctype.h>
00030 #include <sys/types.h>
00031 #include <sys/wait.h>
00032 #include <syslog.h>
00033 #ifdef HAVE_SYS_STAT_H
00034 #include <sys/stat.h>
00035 #endif
00036 
00037 #if TIME_WITH_SYS_TIME
00038 # include <sys/time.h>
00039 # include <time.h>
00040 #else
00041 # if HAVE_SYS_TIME_H
00042 #  include <sys/time.h>
00043 # else
00044 #  include <time.h>
00045 # endif
00046 #endif
00047 
00048 #include <string.h>
00049 #include <limits.h>
00050 #include <libcitadel.h>
00051 #include "auth.h"
00052 #include "citadel.h"
00053 #include "server.h"
00054 #include "database.h"
00055 #include "sysdep_decls.h"
00056 #include "support.h"
00057 #include "room_ops.h"
00058 #include "file_ops.h"
00059 #include "control.h"
00060 #include "msgbase.h"
00061 #include "config.h"
00062 #include "citserver.h"
00063 #include "citadel_dirs.h"
00064 #include "genstamp.h"
00065 #include "threads.h"
00066 #include "citadel_ldap.h"
00067 #include "context.h"
00068 #include "ctdl_module.h"
00069 #include "user_ops.h"
00070 
00071 /* These pipes are used to talk to the chkpwd daemon, which is forked during startup */
00072 int chkpwd_write_pipe[2];
00073 int chkpwd_read_pipe[2];
00074 
00075 
00076 
00077 /*
00078  * getuser()  -  retrieve named user into supplied buffer.
00079  *            returns 0 on success
00080  */
00081 int getuser(struct ctdluser *usbuf, char name[])
00082 {
00083        return CtdlGetUser(usbuf, name);
00084 }
00085 
00086 
00087 /*
00088  * CtdlGetUser()  -  retrieve named user into supplied buffer.
00089  *            returns 0 on success
00090  */
00091 int CtdlGetUserLen(struct ctdluser *usbuf, const char *name, long len)
00092 {
00093 
00094        char usernamekey[USERNAME_SIZE];
00095        struct cdbdata *cdbus;
00096 
00097        if (usbuf != NULL) {
00098               memset(usbuf, 0, sizeof(struct ctdluser));
00099        }
00100 
00101        makeuserkey(usernamekey, name, len);
00102        cdbus = cdb_fetch(CDB_USERS, usernamekey, strlen(usernamekey));
00103 
00104        if (cdbus == NULL) { /* user not found */
00105               return(1);
00106        }
00107        if (usbuf != NULL) {
00108               memcpy(usbuf, cdbus->ptr,
00109                      ((cdbus->len > sizeof(struct ctdluser)) ?
00110                       sizeof(struct ctdluser) : cdbus->len));
00111        }
00112        cdb_free(cdbus);
00113 
00114        return (0);
00115 }
00116 
00117 
00118 int CtdlGetUser(struct ctdluser *usbuf, char *name)
00119 {
00120        return CtdlGetUserLen(usbuf, name, cutuserkey(name));
00121 }
00122 
00123 
00124 /*
00125  * CtdlGetUserLock()  -  same as getuser() but locks the record
00126  */
00127 int CtdlGetUserLock(struct ctdluser *usbuf, char *name)
00128 {
00129        int retcode;
00130 
00131        retcode = CtdlGetUser(usbuf, name);
00132        if (retcode == 0) {
00133               begin_critical_section(S_USERS);
00134        }
00135        return (retcode);
00136 }
00137 
00138 
00139 /*
00140  * lgetuser()  -  same as getuser() but locks the record
00141  */
00142 int lgetuser(struct ctdluser *usbuf, char *name)
00143 {
00144        return CtdlGetUserLock(usbuf, name);
00145 }
00146 
00147 
00148 /*
00149  * CtdlPutUser()  -  write user buffer into the correct place on disk
00150  */
00151 void CtdlPutUser(struct ctdluser *usbuf)
00152 {
00153        char usernamekey[USERNAME_SIZE];
00154 
00155        makeuserkey(usernamekey, 
00156                   usbuf->fullname, 
00157                   cutuserkey(usbuf->fullname));
00158 
00159        usbuf->version = REV_LEVEL;
00160        cdb_store(CDB_USERS,
00161                 usernamekey, strlen(usernamekey),
00162                 usbuf, sizeof(struct ctdluser));
00163 
00164 }
00165 
00166 
00167 /*
00168  * putuser()  -  write user buffer into the correct place on disk
00169  */
00170 void putuser(struct ctdluser *usbuf)
00171 {
00172        CtdlPutUser(usbuf);
00173 }
00174 
00175 
00176 /*
00177  * CtdlPutUserLock()  -  same as putuser() but locks the record
00178  */
00179 void CtdlPutUserLock(struct ctdluser *usbuf)
00180 {
00181        CtdlPutUser(usbuf);
00182        end_critical_section(S_USERS);
00183 }
00184 
00185 
00186 /*
00187  * lputuser()  -  same as putuser() but locks the record
00188  */
00189 void lputuser(struct ctdluser *usbuf)
00190 {
00191        CtdlPutUserLock(usbuf);
00192 }
00193 
00194 
00195 /*
00196  * rename_user()  -  this is tricky because the user's display name is the database key
00197  *
00198  * Returns 0 on success or nonzero if there was an error...
00199  *
00200  */
00201 int rename_user(char *oldname, char *newname) {
00202        int retcode = RENAMEUSER_OK;
00203        struct ctdluser usbuf;
00204 
00205        char oldnamekey[USERNAME_SIZE];
00206        char newnamekey[USERNAME_SIZE];
00207 
00208        /* Create the database keys... */
00209        makeuserkey(oldnamekey, oldname, cutuserkey(oldname));
00210        makeuserkey(newnamekey, newname, cutuserkey(newname));
00211 
00212        /* Lock up and get going */
00213        begin_critical_section(S_USERS);
00214 
00215        /* We cannot rename a user who is currently logged in */
00216        if (CtdlIsUserLoggedIn(oldname)) {
00217               end_critical_section(S_USERS);
00218               return RENAMEUSER_LOGGED_IN;
00219        }
00220 
00221        if (CtdlGetUser(&usbuf, newname) == 0) {
00222               retcode = RENAMEUSER_ALREADY_EXISTS;
00223        }
00224        else {
00225 
00226               if (CtdlGetUser(&usbuf, oldname) != 0) {
00227                      retcode = RENAMEUSER_NOT_FOUND;
00228               }
00229 
00230               else {        /* Sanity checks succeeded.  Now rename the user. */
00231                      if (usbuf.usernum == 0)
00232                      {
00233                             CONM_syslog(LOG_DEBUG, "Can not rename user \"Citadel\".\n");
00234                             retcode = RENAMEUSER_NOT_FOUND;
00235                      } else {
00236                             CON_syslog(LOG_DEBUG, "Renaming <%s> to <%s>\n", oldname, newname);
00237                             cdb_delete(CDB_USERS, oldnamekey, strlen(oldnamekey));
00238                             safestrncpy(usbuf.fullname, newname, sizeof usbuf.fullname);
00239                             CtdlPutUser(&usbuf);
00240                             cdb_store(CDB_USERSBYNUMBER, &usbuf.usernum, sizeof(long),
00241                                    usbuf.fullname, strlen(usbuf.fullname)+1 );
00242 
00243                             retcode = RENAMEUSER_OK;
00244                      }
00245               }
00246        
00247        }
00248 
00249        end_critical_section(S_USERS);
00250        return(retcode);
00251 }
00252 
00253 
00254 
00255 /*
00256  * Index-generating function used by Ctdl[Get|Set]Relationship
00257  */
00258 int GenerateRelationshipIndex(char *IndexBuf,
00259                            long RoomID,
00260                            long RoomGen,
00261                            long UserID)
00262 {
00263 
00264        struct {
00265               long iRoomID;
00266               long iRoomGen;
00267               long iUserID;
00268        } TheIndex;
00269 
00270        TheIndex.iRoomID = RoomID;
00271        TheIndex.iRoomGen = RoomGen;
00272        TheIndex.iUserID = UserID;
00273 
00274        memcpy(IndexBuf, &TheIndex, sizeof(TheIndex));
00275        return (sizeof(TheIndex));
00276 }
00277 
00278 
00279 
00280 /*
00281  * Back end for CtdlSetRelationship()
00282  */
00283 void put_visit(visit *newvisit)
00284 {
00285        char IndexBuf[32];
00286        int IndexLen = 0;
00287 
00288        memset (IndexBuf, 0, sizeof (IndexBuf));
00289        /* Generate an index */
00290        IndexLen = GenerateRelationshipIndex(IndexBuf,
00291                                         newvisit->v_roomnum,
00292                                         newvisit->v_roomgen,
00293                                         newvisit->v_usernum);
00294 
00295        /* Store the record */
00296        cdb_store(CDB_VISIT, IndexBuf, IndexLen,
00297                 newvisit, sizeof(visit)
00298        );
00299 }
00300 
00301 
00302 
00303 
00304 /*
00305  * Define a relationship between a user and a room
00306  */
00307 void CtdlSetRelationship(visit *newvisit,
00308                       struct ctdluser *rel_user,
00309                       struct ctdlroom *rel_room)
00310 {
00311 
00312 
00313        /* We don't use these in Citadel because they're implicit by the
00314         * index, but they must be present if the database is exported.
00315         */
00316        newvisit->v_roomnum = rel_room->QRnumber;
00317        newvisit->v_roomgen = rel_room->QRgen;
00318        newvisit->v_usernum = rel_user->usernum;
00319 
00320        put_visit(newvisit);
00321 }
00322 
00323 /*
00324  * Locate a relationship between a user and a room
00325  */
00326 void CtdlGetRelationship(visit *vbuf,
00327                       struct ctdluser *rel_user,
00328                       struct ctdlroom *rel_room)
00329 {
00330 
00331        char IndexBuf[32];
00332        int IndexLen;
00333        struct cdbdata *cdbvisit;
00334 
00335        /* Generate an index */
00336        IndexLen = GenerateRelationshipIndex(IndexBuf,
00337                                         rel_room->QRnumber,
00338                                         rel_room->QRgen,
00339                                         rel_user->usernum);
00340 
00341        /* Clear out the buffer */
00342        memset(vbuf, 0, sizeof(visit));
00343 
00344        cdbvisit = cdb_fetch(CDB_VISIT, IndexBuf, IndexLen);
00345        if (cdbvisit != NULL) {
00346               memcpy(vbuf, cdbvisit->ptr,
00347                      ((cdbvisit->len > sizeof(visit)) ?
00348                      sizeof(visit) : cdbvisit->len));
00349               cdb_free(cdbvisit);
00350        }
00351        else {
00352               /* If this is the first time the user has seen this room,
00353                * set the view to be the default for the room.
00354                */
00355               vbuf->v_view = rel_room->QRdefaultview;
00356        }
00357 
00358        /* Set v_seen if necessary */
00359        if (vbuf->v_seen[0] == 0) {
00360               snprintf(vbuf->v_seen, sizeof vbuf->v_seen, "*:%ld", vbuf->v_lastseen);
00361        }
00362 }
00363 
00364 
00365 void CtdlMailboxName(char *buf, size_t n, const struct ctdluser *who, const char *prefix)
00366 {
00367        snprintf(buf, n, "%010ld.%s", who->usernum, prefix);
00368 }
00369 
00370 
00371 void MailboxName(char *buf, size_t n, const struct ctdluser *who, const char *prefix)
00372 {
00373        snprintf(buf, n, "%010ld.%s", who->usernum, prefix);
00374 }
00375 
00376 
00377 /*
00378  * Is the user currently logged in an Aide?
00379  */
00380 int is_aide(void)
00381 {
00382        if (CC->user.axlevel >= AxAideU)
00383               return (1);
00384        else
00385               return (0);
00386 }
00387 
00388 
00389 /*
00390  * Is the user currently logged in an Aide *or* the room aide for this room?
00391  */
00392 int is_room_aide(void)
00393 {
00394 
00395        if (!CC->logged_in) {
00396               return (0);
00397        }
00398 
00399        if ((CC->user.axlevel >= AxAideU)
00400            || (CC->room.QRroomaide == CC->user.usernum)) {
00401               return (1);
00402        } else {
00403               return (0);
00404        }
00405 }
00406 
00407 /*
00408  * CtdlGetUserByNumber() -  get user by number
00409  *                   returns 0 if user was found
00410  *
00411  * Note: fetching a user this way requires one additional database operation.
00412  */
00413 int CtdlGetUserByNumber(struct ctdluser *usbuf, long number)
00414 {
00415        struct cdbdata *cdbun;
00416        int r;
00417 
00418        cdbun = cdb_fetch(CDB_USERSBYNUMBER, &number, sizeof(long));
00419        if (cdbun == NULL) {
00420               CON_syslog(LOG_INFO, "User %ld not found\n", number);
00421               return(-1);
00422        }
00423 
00424        CON_syslog(LOG_INFO, "User %ld maps to %s\n", number, cdbun->ptr);
00425        r = CtdlGetUser(usbuf, cdbun->ptr);
00426        cdb_free(cdbun);
00427        return(r);
00428 }
00429 
00430 /*
00431  * getuserbynumber() -      get user by number
00432  *                   returns 0 if user was found
00433  *
00434  * Note: fetching a user this way requires one additional database operation.
00435  */
00436 int getuserbynumber(struct ctdluser *usbuf, long number)
00437 {
00438        return CtdlGetUserByNumber(usbuf, number);
00439 }
00440 
00441 
00442 
00443 /*
00444  * Helper function for rebuild_usersbynumber()
00445  */
00446 void rebuild_ubn_for_user(struct ctdluser *usbuf, void *data) {
00447 
00448        struct ubnlist {
00449               struct ubnlist *next;
00450               char username[USERNAME_SIZE];
00451               long usernum;
00452        };
00453 
00454        static struct ubnlist *u = NULL;
00455        struct ubnlist *ptr = NULL;
00456 
00457        /* Lazy programming here.  Call this function as a ForEachUser backend
00458         * in order to queue up the room names, or call it with a null user
00459         * to make it do the processing.
00460         */
00461        if (usbuf != NULL) {
00462               ptr = (struct ubnlist *) malloc(sizeof (struct ubnlist));
00463               if (ptr == NULL) return;
00464 
00465               ptr->usernum = usbuf->usernum;
00466               safestrncpy(ptr->username, usbuf->fullname, sizeof ptr->username);
00467               ptr->next = u;
00468               u = ptr;
00469               return;
00470        }
00471 
00472        while (u != NULL) {
00473               CON_syslog(LOG_DEBUG, "Rebuilding usersbynumber index %10ld : %s\n",
00474                      u->usernum, u->username);
00475               cdb_store(CDB_USERSBYNUMBER, &u->usernum, sizeof(long), u->username, strlen(u->username)+1);
00476 
00477               ptr = u;
00478               u = u->next;
00479               free(ptr);
00480        }
00481 }
00482 
00483 
00484 
00485 /*
00486  * Rebuild the users-by-number index
00487  */
00488 void rebuild_usersbynumber(void) {
00489        cdb_trunc(CDB_USERSBYNUMBER);                    /* delete the old indices */
00490        ForEachUser(rebuild_ubn_for_user, NULL);  /* enumerate the users */
00491        rebuild_ubn_for_user(NULL, NULL);         /* and index them */
00492 }
00493 
00494 
00495 
00496 /*
00497  * getuserbyuid()  -     get user by system uid (for PAM mode authentication)
00498  *                   returns 0 if user was found
00499  *
00500  * WARNING: don't use this function unless you absolutely have to.  It does
00501  *       a sequential search and therefore is computationally expensive.
00502  */
00503 int getuserbyuid(struct ctdluser *usbuf, uid_t number)
00504 {
00505        struct cdbdata *cdbus;
00506 
00507        cdb_rewind(CDB_USERS);
00508 
00509        while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) {
00510               memset(usbuf, 0, sizeof(struct ctdluser));
00511               memcpy(usbuf, cdbus->ptr,
00512                      ((cdbus->len > sizeof(struct ctdluser)) ?
00513                      sizeof(struct ctdluser) : cdbus->len));
00514               cdb_free(cdbus);
00515               if (usbuf->uid == number) {
00516                      cdb_close_cursor(CDB_USERS);
00517                      return (0);
00518               }
00519        }
00520        return (-1);
00521 }
00522 
00523 /*
00524  * Back end for cmd_user() and its ilk
00525  *
00526  * NOTE: "authname" should only be used if we are attempting to use the "master user" feature
00527  */
00528 int CtdlLoginExistingUser(char *authname, const char *trythisname)
00529 {
00530        char username[SIZ];
00531        int found_user;
00532        long len;
00533 
00534        CON_syslog(LOG_DEBUG, "CtdlLoginExistingUser(%s, %s)\n", authname, trythisname);
00535 
00536        if ((CC->logged_in)) {
00537               return login_already_logged_in;
00538        }
00539 
00540        if (trythisname == NULL) return login_not_found;
00541        
00542        if (!strncasecmp(trythisname, "SYS_", 4))
00543        {
00544               CON_syslog(LOG_DEBUG, "System user \"%s\" is not allowed to log in.\n", trythisname);
00545               return login_not_found;
00546        }
00547 
00548        /* If a "master user" is defined, handle its authentication if specified */
00549        CC->is_master = 0;
00550        if (strlen(config.c_master_user) > 0) if (strlen(config.c_master_pass) > 0) if (authname) {
00551               if (!strcasecmp(authname, config.c_master_user)) {
00552                      CC->is_master = 1;
00553               }
00554        }
00555 
00556        /* Continue attempting user validation... */
00557        safestrncpy(username, trythisname, sizeof (username));
00558        striplt(username);
00559        len = cutuserkey(username);
00560 
00561        if (IsEmptyStr(username)) {
00562               return login_not_found;
00563        }
00564 
00565        if (config.c_auth_mode == AUTHMODE_HOST) {
00566 
00567               /* host auth mode */
00568 
00569               struct passwd pd;
00570               struct passwd *tempPwdPtr;
00571               char pwdbuffer[256];
00572        
00573               CON_syslog(LOG_DEBUG, "asking host about <%s>\n", username);
00574 #ifdef HAVE_GETPWNAM_R
00575 #ifdef SOLARIS_GETPWUID
00576               CON_syslog(LOG_DEBUG, "Calling getpwnam_r()\n");
00577               tempPwdPtr = getpwnam_r(username, &pd, pwdbuffer, sizeof pwdbuffer);
00578 #else // SOLARIS_GETPWUID
00579               CONM_syslog(LOG_DEBUG, "Calling getpwnam_r()\n");
00580               getpwnam_r(username, &pd, pwdbuffer, sizeof pwdbuffer, &tempPwdPtr);
00581 #endif // SOLARIS_GETPWUID
00582 #else // HAVE_GETPWNAM_R
00583               CON_syslog(LOG_DEBUG, "SHOULD NEVER GET HERE!!!\n");
00584               tempPwdPtr = NULL;
00585 #endif // HAVE_GETPWNAM_R
00586               if (tempPwdPtr == NULL) {
00587                      CON_syslog(LOG_DEBUG, "no such user <%s>\n", username);
00588                      return login_not_found;
00589               }
00590        
00591               /* Locate the associated Citadel account.
00592                * If not found, make one attempt to create it.
00593                */
00594               found_user = getuserbyuid(&CC->user, pd.pw_uid);
00595               CON_syslog(LOG_DEBUG, "found it: uid=%ld, gecos=%s here: %d\n",
00596                      (long)pd.pw_uid, pd.pw_gecos, found_user);
00597               if (found_user != 0) {
00598                      len = cutuserkey(username);
00599                      create_user(username, len, 0);
00600                      found_user = getuserbyuid(&CC->user, pd.pw_uid);
00601               }
00602 
00603        }
00604 
00605 #ifdef HAVE_LDAP
00606        else if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
00607        
00608               /* LDAP auth mode */
00609 
00610               uid_t ldap_uid;
00611               char ldap_cn[256];
00612               char ldap_dn[256];
00613 
00614               found_user = CtdlTryUserLDAP(username, ldap_dn, sizeof ldap_dn, ldap_cn, sizeof ldap_cn, &ldap_uid);
00615               if (found_user != 0) {
00616                      return login_not_found;
00617               }
00618 
00619               found_user = getuserbyuid(&CC->user, ldap_uid);
00620               if (found_user != 0) {
00621                      create_user(username, len, 0);
00622                      found_user = getuserbyuid(&CC->user, ldap_uid);
00623               }
00624 
00625               if (found_user == 0) {
00626                      if (CC->ldap_dn != NULL) free(CC->ldap_dn);
00627                      CC->ldap_dn = strdup(ldap_dn);
00628               }
00629 
00630        }
00631 #endif
00632 
00633        else {
00634               /* native auth mode */
00635 
00636               struct recptypes *valid = NULL;
00637        
00638               /* First, try to log in as if the supplied name is a display name */
00639               found_user = CtdlGetUser(&CC->user, username);
00640        
00641               /* If that didn't work, try to log in as if the supplied name
00642               * is an e-mail address
00643               */
00644               if (found_user != 0) {
00645                      valid = validate_recipients(username, NULL, 0);
00646                      if (valid != NULL) {
00647                             if (valid->num_local == 1) {
00648                                    found_user = CtdlGetUser(&CC->user, valid->recp_local);
00649                             }
00650                             free_recipients(valid);
00651                      }
00652               }
00653        }
00654 
00655        /* Did we find something? */
00656        if (found_user == 0) {
00657               if (((CC->nologin)) && (CC->user.axlevel < AxAideU)) {
00658                      return login_too_many_users;
00659               } else {
00660                      safestrncpy(CC->curr_user, CC->user.fullname,
00661                                    sizeof CC->curr_user);
00662                      return login_ok;
00663               }
00664        }
00665        return login_not_found;
00666 }
00667 
00668 
00669 
00670 /*
00671  * USER cmd
00672  */
00673 void cmd_user(char *cmdbuf)
00674 {
00675        char username[256];
00676        int a;
00677 
00678        CON_syslog(LOG_DEBUG, "cmd_user(%s)\n", cmdbuf);
00679        extract_token(username, cmdbuf, 0, '|', sizeof username);
00680        CON_syslog(LOG_DEBUG, "username: %s\n", username);
00681        striplt(username);
00682        CON_syslog(LOG_DEBUG, "username: %s\n", username);
00683 
00684        a = CtdlLoginExistingUser(NULL, username);
00685        switch (a) {
00686        case login_already_logged_in:
00687               cprintf("%d Already logged in.\n", ERROR + ALREADY_LOGGED_IN);
00688               return;
00689        case login_too_many_users:
00690               cprintf("%d %s: "
00691                      "Too many users are already online "
00692                      "(maximum is %d)\n",
00693                      ERROR + MAX_SESSIONS_EXCEEDED,
00694                      config.c_nodename, config.c_maxsessions);
00695               return;
00696        case login_ok:
00697               cprintf("%d Password required for %s\n",
00698                      MORE_DATA, CC->curr_user);
00699               return;
00700        case login_not_found:
00701               cprintf("%d %s not found.\n", ERROR + NO_SUCH_USER, username);
00702               return;
00703        default:
00704               cprintf("%d Internal error\n", ERROR + INTERNAL_ERROR);
00705        }
00706 }
00707 
00708 
00709 
00710 /*
00711  * session startup code which is common to both cmd_pass() and cmd_newu()
00712  */
00713 void do_login(void)
00714 {
00715        struct CitContext *CCC = CC;
00716 
00717        CCC->logged_in = 1;
00718        CON_syslog(LOG_NOTICE, "<%s> logged in\n", CCC->curr_user);
00719 
00720        CtdlGetUserLock(&CCC->user, CCC->curr_user);
00721        ++(CCC->user.timescalled);
00722        CCC->previous_login = CCC->user.lastcall;
00723        time(&CCC->user.lastcall);
00724 
00725        /* If this user's name is the name of the system administrator
00726         * (as specified in setup), automatically assign access level 6.
00727         */
00728        if (!strcasecmp(CCC->user.fullname, config.c_sysadm)) {
00729               CCC->user.axlevel = AxAideU;
00730        }
00731 
00732        /* If we're authenticating off the host system, automatically give
00733         * root the highest level of access.
00734         */
00735        if (config.c_auth_mode == AUTHMODE_HOST) {
00736               if (CCC->user.uid == 0) {
00737                      CCC->user.axlevel = AxAideU;
00738               }
00739        }
00740 
00741        CtdlPutUserLock(&CCC->user);
00742 
00743        /*
00744         * Populate CCC->cs_inet_email with a default address.  This will be
00745         * overwritten with the user's directory address, if one exists, when
00746         * the vCard module's login hook runs.
00747         */
00748        snprintf(CCC->cs_inet_email, sizeof CCC->cs_inet_email, "%s@%s",
00749               CCC->user.fullname, config.c_fqdn);
00750        convert_spaces_to_underscores(CCC->cs_inet_email);
00751 
00752        /* Create any personal rooms required by the system.
00753         * (Technically, MAILROOM should be there already, but just in case...)
00754         */
00755        CtdlCreateRoom(MAILROOM, 4, "", 0, 1, 0, VIEW_MAILBOX);
00756        CtdlCreateRoom(SENTITEMS, 4, "", 0, 1, 0, VIEW_MAILBOX);
00757        CtdlCreateRoom(USERTRASHROOM, 4, "", 0, 1, 0, VIEW_MAILBOX);
00758        CtdlCreateRoom(USERDRAFTROOM, 4, "", 0, 1, 0, VIEW_MAILBOX);
00759 
00760        /* Run any startup routines registered by loadable modules */
00761        PerformSessionHooks(EVT_LOGIN);
00762 
00763        /* Enter the lobby */
00764        CtdlUserGoto(config.c_baseroom, 0, 0, NULL, NULL);
00765 }
00766 
00767 
00768 void logged_in_response(void)
00769 {
00770        cprintf("%d %s|%d|%ld|%ld|%u|%ld|%ld\n",
00771               CIT_OK, CC->user.fullname, CC->user.axlevel,
00772               CC->user.timescalled, CC->user.posted,
00773               CC->user.flags, CC->user.usernum,
00774               CC->previous_login);
00775 }
00776 
00777 
00778 
00779 void CtdlUserLogout(void)
00780 {
00781        CitContext *CCC = MyContext();
00782 
00783        CON_syslog(LOG_DEBUG, "CtdlUserLogout() logging out <%s> from session %d",
00784                  CCC->curr_user, CCC->cs_pid
00785        );
00786 
00787        /*
00788         * If there is a download in progress, abort it.
00789         */
00790        if (CCC->download_fp != NULL) {
00791               fclose(CCC->download_fp);
00792               CCC->download_fp = NULL;
00793        }
00794 
00795        /*
00796         * If there is an upload in progress, abort it.
00797         */
00798        if (CCC->upload_fp != NULL) {
00799               abort_upl(CCC);
00800        }
00801 
00802        /* Run any hooks registered by modules... */
00803        PerformSessionHooks(EVT_LOGOUT);
00804        
00805        /*
00806         * Clear out some session data.  Most likely, the CitContext for this
00807         * session is about to get nuked when the session disconnects, but
00808         * since it's possible to log in again without reconnecting, we cannot
00809         * make that assumption.
00810         */
00811        strcpy(CCC->fake_username, "");
00812        strcpy(CCC->fake_hostname, "");
00813        strcpy(CCC->fake_roomname, "");
00814        CCC->logged_in = 0;
00815 
00816        /* Check to see if the user was deleted whilst logged in and purge them if necessary */
00817        if ((CCC->user.axlevel == AxDeleted) && (CCC->user.usernum))
00818               purge_user(CCC->user.fullname);
00819 
00820        /* Clear out the user record in memory so we don't behave like a ghost */
00821        memset(&CCC->user, 0, sizeof(struct ctdluser));
00822        CCC->curr_user[0] = 0;
00823        CCC->is_master = 0;
00824        CCC->cs_inet_email[0] = 0;
00825        CCC->cs_inet_other_emails[0] = 0;
00826        CCC->cs_inet_fn[0] = 0;
00827        CCC->fake_username[0] = 0;
00828        CCC->fake_hostname[0] = 0;
00829        CCC->fake_roomname[0] = 0;
00830        
00831 
00832        /* Free any output buffers */
00833        unbuffer_output();
00834 }
00835 
00836 
00837 /*
00838  * Validate a password on the host unix system by talking to the chkpwd daemon
00839  */
00840 static int validpw(uid_t uid, const char *pass)
00841 {
00842        char buf[256];
00843        int rv = 0;
00844 
00845        if (IsEmptyStr(pass)) {
00846               CON_syslog(LOG_DEBUG, "Refusing to chkpwd for uid=%d with empty password.\n", uid);
00847               return 0;
00848        }
00849 
00850        CON_syslog(LOG_DEBUG, "Validating password for uid=%d using chkpwd...\n", uid);
00851 
00852        begin_critical_section(S_CHKPWD);
00853        rv = write(chkpwd_write_pipe[1], &uid, sizeof(uid_t));
00854        if (rv == -1) {
00855               CON_syslog(LOG_EMERG, "Communicatino with chkpwd broken: %s\n", strerror(errno));
00856               end_critical_section(S_CHKPWD);
00857               return 0;
00858        }
00859        rv = write(chkpwd_write_pipe[1], pass, 256);
00860        if (rv == -1) {
00861               CON_syslog(LOG_EMERG, "Communicatino with chkpwd broken: %s\n", strerror(errno));
00862               end_critical_section(S_CHKPWD);
00863               return 0;
00864        }
00865        rv = read(chkpwd_read_pipe[0], buf, 4);
00866        if (rv == -1) {
00867               CON_syslog(LOG_EMERG, "Communicatino with chkpwd broken: %s\n", strerror(errno));
00868               end_critical_section(S_CHKPWD);
00869               return 0;
00870        }
00871        end_critical_section(S_CHKPWD);
00872 
00873        if (!strncmp(buf, "PASS", 4)) {
00874               CONM_syslog(LOG_DEBUG, "...pass\n");
00875               return(1);
00876        }
00877 
00878        CONM_syslog(LOG_DEBUG, "...fail\n");
00879        return 0;
00880 }
00881 
00882 /* 
00883  * Start up the chkpwd daemon so validpw() has something to talk to
00884  */
00885 void start_chkpwd_daemon(void) {
00886        pid_t chkpwd_pid;
00887        struct stat filestats;
00888        int i;
00889 
00890        CONM_syslog(LOG_DEBUG, "Starting chkpwd daemon for host authentication mode\n");
00891 
00892        if ((stat(file_chkpwd, &filestats)==-1) ||
00893            (filestats.st_size==0)){
00894               printf("didn't find chkpwd daemon in %s: %s\n", file_chkpwd, strerror(errno));
00895               abort();
00896        }
00897        if (pipe(chkpwd_write_pipe) != 0) {
00898               CON_syslog(LOG_EMERG, "Unable to create pipe for chkpwd daemon: %s\n", strerror(errno));
00899               abort();
00900        }
00901        if (pipe(chkpwd_read_pipe) != 0) {
00902               CON_syslog(LOG_EMERG, "Unable to create pipe for chkpwd daemon: %s\n", strerror(errno));
00903               abort();
00904        }
00905 
00906        chkpwd_pid = fork();
00907        if (chkpwd_pid < 0) {
00908               CON_syslog(LOG_EMERG, "Unable to fork chkpwd daemon: %s\n", strerror(errno));
00909               abort();
00910        }
00911        if (chkpwd_pid == 0) {
00912               CONM_syslog(LOG_DEBUG, "Now calling dup2() write\n");
00913               dup2(chkpwd_write_pipe[0], 0);
00914               CONM_syslog(LOG_DEBUG, "Now calling dup2() write\n");
00915               dup2(chkpwd_read_pipe[1], 1);
00916               CONM_syslog(LOG_DEBUG, "Now closing stuff\n");
00917               for (i=2; i<256; ++i) close(i);
00918               CON_syslog(LOG_DEBUG, "Now calling execl(%s)\n", file_chkpwd);
00919               execl(file_chkpwd, file_chkpwd, NULL);
00920               CON_syslog(LOG_EMERG, "Unable to exec chkpwd daemon: %s\n", strerror(errno));
00921               abort();
00922               exit(errno);
00923        }
00924 }
00925 
00926 
00927 int CtdlTryPassword(const char *password, long len)
00928 {
00929        int code;
00930        CitContext *CCC = CC;
00931 
00932        if ((CCC->logged_in)) {
00933               CONM_syslog(LOG_WARNING, "CtdlTryPassword: already logged in\n");
00934               return pass_already_logged_in;
00935        }
00936        if (!strcmp(CCC->curr_user, NLI)) {
00937               CONM_syslog(LOG_WARNING, "CtdlTryPassword: no user selected\n");
00938               return pass_no_user;
00939        }
00940        if (CtdlGetUser(&CCC->user, CCC->curr_user)) {
00941               CONM_syslog(LOG_ERR, "CtdlTryPassword: internal error\n");
00942               return pass_internal_error;
00943        }
00944        if (password == NULL) {
00945               CONM_syslog(LOG_INFO, "CtdlTryPassword: NULL password string supplied\n");
00946               return pass_wrong_password;
00947        }
00948 
00949        if (CCC->is_master) {
00950               code = strcmp(password, config.c_master_pass);
00951        }
00952 
00953        else if (config.c_auth_mode == AUTHMODE_HOST) {
00954 
00955               /* host auth mode */
00956 
00957               if (validpw(CCC->user.uid, password)) {
00958                      code = 0;
00959 
00960                      /*
00961                       * sooper-seekrit hack: populate the password field in the
00962                       * citadel database with the password that the user typed,
00963                       * if it's correct.  This allows most sites to convert from
00964                       * host auth to native auth if they want to.  If you think
00965                       * this is a security hazard, comment it out.
00966                       */
00967 
00968                      CtdlGetUserLock(&CCC->user, CCC->curr_user);
00969                      safestrncpy(CCC->user.password, password, sizeof CCC->user.password);
00970                      CtdlPutUserLock(&CCC->user);
00971 
00972                      /*
00973                       * (sooper-seekrit hack ends here)
00974                       */
00975 
00976               }
00977               else {
00978                      code = (-1);
00979               }
00980        }
00981 
00982 #ifdef HAVE_LDAP
00983        else if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
00984 
00985               /* LDAP auth mode */
00986 
00987               if ((CCC->ldap_dn) && (!CtdlTryPasswordLDAP(CCC->ldap_dn, password))) {
00988                      code = 0;
00989               }
00990               else {
00991                      code = (-1);
00992               }
00993        }
00994 #endif
00995 
00996        else {
00997 
00998               /* native auth mode */
00999               char *pw;
01000 
01001               pw = (char*) malloc(len + 1);
01002               memcpy(pw, password, len + 1);
01003               strproc(pw);
01004               strproc(CCC->user.password);
01005               code = strcasecmp(CCC->user.password, pw);
01006               if (code != 0) {
01007                      strproc(pw);
01008                      strproc(CCC->user.password);
01009                      code = strcasecmp(CCC->user.password, pw);
01010               }
01011               free (pw);
01012        }
01013 
01014        if (!code) {
01015               do_login();
01016               return pass_ok;
01017        } else {
01018               CON_syslog(LOG_WARNING, "Bad password specified for <%s> Service <%s> Port <%ld> Remote <%s / %s>\n",
01019                         CCC->curr_user,
01020                         CCC->ServiceName,
01021                         CCC->tcp_port,
01022                         CCC->cs_host,
01023                         CCC->cs_addr);
01024 
01025 
01026 //citserver[5610]: Bad password specified for <willi> Service <citadel-TCP> Remote <PotzBlitz / >
01027 
01028               return pass_wrong_password;
01029        }
01030 }
01031 
01032 
01033 void cmd_pass(char *buf)
01034 {
01035        char password[SIZ];
01036        int a;
01037        long len;
01038 
01039        memset(password, 0, sizeof(password));
01040        len = extract_token(password, buf, 0, '|', sizeof password);
01041        a = CtdlTryPassword(password, len);
01042 
01043        switch (a) {
01044        case pass_already_logged_in:
01045               cprintf("%d Already logged in.\n", ERROR + ALREADY_LOGGED_IN);
01046               return;
01047        case pass_no_user:
01048               cprintf("%d You must send a name with USER first.\n",
01049                      ERROR + USERNAME_REQUIRED);
01050               return;
01051        case pass_wrong_password:
01052               cprintf("%d Wrong password.\n", ERROR + PASSWORD_REQUIRED);
01053               return;
01054        case pass_ok:
01055               logged_in_response();
01056               return;
01057        }
01058 }
01059 
01060 
01061 
01062 /*
01063  * Delete a user record *and* all of its related resources.
01064  */
01065 int purge_user(char pname[])
01066 {
01067        char filename[64];
01068        struct ctdluser usbuf;
01069        char usernamekey[USERNAME_SIZE];
01070 
01071        makeuserkey(usernamekey, pname, cutuserkey(pname));
01072 
01073        /* If the name is empty we can't find them in the DB any way so just return */
01074        if (IsEmptyStr(pname))
01075               return (ERROR + NO_SUCH_USER);
01076 
01077        if (CtdlGetUser(&usbuf, pname) != 0) {
01078               CON_syslog(LOG_ERR, "Cannot purge user <%s> - not found\n", pname);
01079               return (ERROR + NO_SUCH_USER);
01080        }
01081        /* Don't delete a user who is currently logged in.  Instead, just
01082         * set the access level to 0, and let the account get swept up
01083         * during the next purge.
01084         */
01085        if (CtdlIsUserLoggedInByNum(usbuf.usernum)) {
01086               CON_syslog(LOG_WARNING, "User <%s> is logged in; not deleting.\n", pname);
01087               usbuf.axlevel = AxDeleted;
01088               CtdlPutUser(&usbuf);
01089               return (1);
01090        }
01091        CON_syslog(LOG_NOTICE, "Deleting user <%s>\n", pname);
01092 
01093 /*
01094  * FIXME:
01095  * This should all be wrapped in a S_USERS mutex.
01096  * Without the mutex the user could log in before we get to the next function
01097  * That would truly mess things up :-(
01098  * I would like to see the S_USERS start before the CtdlIsUserLoggedInByNum() above
01099  * and end after the user has been deleted from the database, below.
01100  * Question is should we enter the EVT_PURGEUSER whilst S_USERS is active?
01101  */
01102 
01103        /* Perform any purge functions registered by server extensions */
01104        PerformUserHooks(&usbuf, EVT_PURGEUSER);
01105 
01106        /* delete any existing user/room relationships */
01107        cdb_delete(CDB_VISIT, &usbuf.usernum, sizeof(long));
01108 
01109        /* delete the users-by-number index record */
01110        cdb_delete(CDB_USERSBYNUMBER, &usbuf.usernum, sizeof(long));
01111 
01112        /* delete the userlog entry */
01113        cdb_delete(CDB_USERS, usernamekey, strlen(usernamekey));
01114 
01115        /* remove the user's bio file */
01116        snprintf(filename, 
01117                       sizeof filename, 
01118                       "%s/%ld",
01119                       ctdl_bio_dir,
01120                       usbuf.usernum);
01121        unlink(filename);
01122 
01123        /* remove the user's picture */
01124        snprintf(filename, 
01125                       sizeof filename, 
01126                       "%s/%ld.gif",
01127                       ctdl_image_dir,
01128                       usbuf.usernum);
01129        unlink(filename);
01130 
01131        return (0);
01132 }
01133 
01134 
01135 int internal_create_user (const char *username, long len, struct ctdluser *usbuf, uid_t uid)
01136 {
01137        if (!CtdlGetUserLen(usbuf, username, len)) {
01138               return (ERROR + ALREADY_EXISTS);
01139        }
01140 
01141        /* Go ahead and initialize a new user record */
01142        memset(usbuf, 0, sizeof(struct ctdluser));
01143        safestrncpy(usbuf->fullname, username, sizeof usbuf->fullname);
01144        strcpy(usbuf->password, "");
01145        usbuf->uid = uid;
01146 
01147        /* These are the default flags on new accounts */
01148        usbuf->flags = US_LASTOLD | US_DISAPPEAR | US_PAGINATOR | US_FLOORS;
01149 
01150        usbuf->timescalled = 0;
01151        usbuf->posted = 0;
01152        usbuf->axlevel = config.c_initax;
01153        usbuf->lastcall = time(NULL);
01154 
01155        /* fetch a new user number */
01156        usbuf->usernum = get_new_user_number();
01157 
01158        /* add user to the database */
01159        CtdlPutUser(usbuf);
01160        cdb_store(CDB_USERSBYNUMBER, &usbuf->usernum, sizeof(long), usbuf->fullname, strlen(usbuf->fullname)+1);
01161 
01162        return 0;
01163 }
01164 
01165 
01166 
01167 /*
01168  * create_user()  -  back end processing to create a new user
01169  *
01170  * Set 'newusername' to the desired account name.
01171  * Set 'become_user' to nonzero if this is self-service account creation and we want
01172  * to actually log in as the user we just created, otherwise set it to 0.
01173  */
01174 int create_user(const char *newusername, long len, int become_user)
01175 {
01176        struct ctdluser usbuf;
01177        struct ctdlroom qrbuf;
01178        char username[256];
01179        char mailboxname[ROOMNAMELEN];
01180        char buf[SIZ];
01181        int retval;
01182        uid_t uid = (-1);
01183        
01184 
01185        safestrncpy(username, newusername, sizeof username);
01186        strproc(username);
01187 
01188        
01189        if (config.c_auth_mode == AUTHMODE_HOST) {
01190 
01191               /* host auth mode */
01192 
01193               struct passwd pd;
01194               struct passwd *tempPwdPtr;
01195               char pwdbuffer[SIZ];
01196        
01197 #ifdef HAVE_GETPWNAM_R
01198 #ifdef SOLARIS_GETPWUID
01199               tempPwdPtr = getpwnam_r(username, &pd, pwdbuffer, sizeof(pwdbuffer));
01200 #else // SOLARIS_GETPWUID
01201               getpwnam_r(username, &pd, pwdbuffer, sizeof pwdbuffer, &tempPwdPtr);
01202 #endif // SOLARIS_GETPWUID
01203 #else // HAVE_GETPWNAM_R
01204               tempPwdPtr = NULL;
01205 #endif // HAVE_GETPWNAM_R
01206               if (tempPwdPtr != NULL) {
01207                      extract_token(username, pd.pw_gecos, 0, ',', sizeof username);
01208                      uid = pd.pw_uid;
01209                      if (IsEmptyStr (username))
01210                      {
01211                             safestrncpy(username, pd.pw_name, sizeof username);
01212                             len = cutuserkey(username);
01213                      }
01214               }
01215               else {
01216                      return (ERROR + NO_SUCH_USER);
01217               }
01218        }
01219 
01220 #ifdef HAVE_LDAP
01221        if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
01222               if (CtdlTryUserLDAP(username, NULL, 0, username, sizeof username, &uid) != 0) {
01223                      return(ERROR + NO_SUCH_USER);
01224               }
01225        }
01226 #endif /* HAVE_LDAP */
01227        
01228        if ((retval = internal_create_user(username, len, &usbuf, uid)) != 0)
01229               return retval;
01230        
01231        /*
01232         * Give the user a private mailbox and a configuration room.
01233         * Make the latter an invisible system room.
01234         */
01235        CtdlMailboxName(mailboxname, sizeof mailboxname, &usbuf, MAILROOM);
01236        CtdlCreateRoom(mailboxname, 5, "", 0, 1, 1, VIEW_MAILBOX);
01237 
01238        CtdlMailboxName(mailboxname, sizeof mailboxname, &usbuf, USERCONFIGROOM);
01239        CtdlCreateRoom(mailboxname, 5, "", 0, 1, 1, VIEW_BBS);
01240        if (CtdlGetRoomLock(&qrbuf, mailboxname) == 0) {
01241               qrbuf.QRflags2 |= QR2_SYSTEM;
01242               CtdlPutRoomLock(&qrbuf);
01243        }
01244 
01245        /* Perform any create functions registered by server extensions */
01246        PerformUserHooks(&usbuf, EVT_NEWUSER);
01247 
01248        /* Everything below this line can be bypassed if administratively
01249         * creating a user, instead of doing self-service account creation
01250         */
01251 
01252        if (become_user) {
01253               /* Now become the user we just created */
01254               memcpy(&CC->user, &usbuf, sizeof(struct ctdluser));
01255               safestrncpy(CC->curr_user, username, sizeof CC->curr_user);
01256               do_login();
01257        
01258               /* Check to make sure we're still who we think we are */
01259               if (CtdlGetUser(&CC->user, CC->curr_user)) {
01260                      return (ERROR + INTERNAL_ERROR);
01261               }
01262        }
01263        
01264        snprintf(buf, SIZ, 
01265               "New user account <%s> has been created, from host %s [%s].\n",
01266               username,
01267               CC->cs_host,
01268               CC->cs_addr
01269        );
01270        CtdlAideMessage(buf, "User Creation Notice");
01271        CON_syslog(LOG_NOTICE, "New user <%s> created\n", username);
01272        return (0);
01273 }
01274 
01275 
01276 
01277 /*
01278  * cmd_newu()  -  create a new user account and log in as that user
01279  */
01280 void cmd_newu(char *cmdbuf)
01281 {
01282        int a;
01283        long len;
01284        char username[SIZ];
01285 
01286        if (config.c_auth_mode != AUTHMODE_NATIVE) {
01287               cprintf("%d This system does not use native mode authentication.\n",
01288                      ERROR + NOT_HERE);
01289               return;
01290        }
01291 
01292        if (config.c_disable_newu) {
01293               cprintf("%d Self-service user account creation "
01294                      "is disabled on this system.\n", ERROR + NOT_HERE);
01295               return;
01296        }
01297 
01298        if (CC->logged_in) {
01299               cprintf("%d Already logged in.\n", ERROR + ALREADY_LOGGED_IN);
01300               return;
01301        }
01302        if (CC->nologin) {
01303               cprintf("%d %s: Too many users are already online (maximum is %d)\n",
01304                      ERROR + MAX_SESSIONS_EXCEEDED,
01305                      config.c_nodename, config.c_maxsessions);
01306        }
01307        extract_token(username, cmdbuf, 0, '|', sizeof username);
01308        strproc(username);
01309        len = cutuserkey(username);
01310 
01311        if (IsEmptyStr(username)) {
01312               cprintf("%d You must supply a user name.\n", ERROR + USERNAME_REQUIRED);
01313               return;
01314        }
01315 
01316        if ((!strcasecmp(username, "bbs")) ||
01317            (!strcasecmp(username, "new")) ||
01318            (!strcasecmp(username, "."))) {
01319               cprintf("%d '%s' is an invalid login name.\n", ERROR + ILLEGAL_VALUE, username);
01320               return;
01321        }
01322 
01323        a = create_user(username, len, 1);
01324 
01325        if (a == 0) {
01326               logged_in_response();
01327        } else if (a == ERROR + ALREADY_EXISTS) {
01328               cprintf("%d '%s' already exists.\n",
01329                      ERROR + ALREADY_EXISTS, username);
01330               return;
01331        } else if (a == ERROR + INTERNAL_ERROR) {
01332               cprintf("%d Internal error - user record disappeared?\n",
01333                      ERROR + INTERNAL_ERROR);
01334               return;
01335        } else {
01336               cprintf("%d unknown error\n", ERROR + INTERNAL_ERROR);
01337        }
01338 }
01339 
01340 
01341 /*
01342  * set password - back end api code
01343  */
01344 void CtdlSetPassword(char *new_pw)
01345 {
01346        CtdlGetUserLock(&CC->user, CC->curr_user);
01347        safestrncpy(CC->user.password, new_pw, sizeof(CC->user.password));
01348        CtdlPutUserLock(&CC->user);
01349        CON_syslog(LOG_INFO, "Password changed for user <%s>\n", CC->curr_user);
01350        PerformSessionHooks(EVT_SETPASS);
01351 }
01352 
01353 
01354 /*
01355  * set password - citadel protocol implementation
01356  */
01357 void cmd_setp(char *new_pw)
01358 {
01359        if (CtdlAccessCheck(ac_logged_in)) {
01360               return;
01361        }
01362        if ( (CC->user.uid != CTDLUID) && (CC->user.uid != (-1)) ) {
01363               cprintf("%d Not allowed.  Use the 'passwd' command.\n", ERROR + NOT_HERE);
01364               return;
01365        }
01366        if (CC->is_master) {
01367               cprintf("%d The master prefix password cannot be changed with this command.\n",
01368                      ERROR + NOT_HERE);
01369               return;
01370        }
01371 
01372        if (!strcasecmp(new_pw, "GENERATE_RANDOM_PASSWORD")) {
01373               char random_password[17];
01374               snprintf(random_password, sizeof random_password, "%08lx%08lx", random(), random());
01375               CtdlSetPassword(random_password);
01376               cprintf("%d %s\n", CIT_OK, random_password);
01377        }
01378        else {
01379               strproc(new_pw);
01380               if (IsEmptyStr(new_pw)) {
01381                      cprintf("%d Password unchanged.\n", CIT_OK);
01382                      return;
01383               }
01384               CtdlSetPassword(new_pw);
01385               cprintf("%d Password changed.\n", CIT_OK);
01386        }
01387 }
01388 
01389 
01390 /*
01391  * cmd_creu() - administratively create a new user account (do not log in to it)
01392  */
01393 void cmd_creu(char *cmdbuf)
01394 {
01395        int a;
01396        long len;
01397        char username[SIZ];
01398        char password[SIZ];
01399        struct ctdluser tmp;
01400 
01401        if (CtdlAccessCheck(ac_aide)) {
01402               return;
01403        }
01404 
01405        extract_token(username, cmdbuf, 0, '|', sizeof username);
01406        strproc(username);
01407        strproc(password);
01408        if (IsEmptyStr(username)) {
01409               cprintf("%d You must supply a user name.\n", ERROR + USERNAME_REQUIRED);
01410               return;
01411        }
01412        len = cutuserkey(username);
01413 
01414 
01415        extract_token(password, cmdbuf, 1, '|', sizeof password);
01416 
01417        a = create_user(username, len, 0);
01418 
01419        if (a == 0) {
01420               if (!IsEmptyStr(password)) {
01421                      CtdlGetUserLock(&tmp, username);
01422                      safestrncpy(tmp.password, password, sizeof(tmp.password));
01423                      CtdlPutUserLock(&tmp);
01424               }
01425               cprintf("%d User '%s' created %s.\n", CIT_OK, username,
01426                             (!IsEmptyStr(password)) ? "and password set" :
01427                             "with no password");
01428               return;
01429        } else if (a == ERROR + ALREADY_EXISTS) {
01430               cprintf("%d '%s' already exists.\n", ERROR + ALREADY_EXISTS, username);
01431               return;
01432        } else if ( (config.c_auth_mode != AUTHMODE_NATIVE) && (a == ERROR + NO_SUCH_USER) ) {
01433               cprintf("%d User accounts are not created within Citadel in host authentication mode.\n",
01434                      ERROR + NO_SUCH_USER);
01435               return;
01436        } else {
01437               cprintf("%d An error occurred creating the user account.\n", ERROR + INTERNAL_ERROR);
01438        }
01439 }
01440 
01441 
01442 
01443 /*
01444  * get user parameters
01445  */
01446 void cmd_getu(char *cmdbuf)
01447 {
01448 
01449        if (CtdlAccessCheck(ac_logged_in))
01450               return;
01451 
01452        CtdlGetUser(&CC->user, CC->curr_user);
01453        cprintf("%d 80|24|%d|\n",
01454               CIT_OK,
01455               (CC->user.flags & US_USER_SET)
01456        );
01457 }
01458 
01459 /*
01460  * set user parameters
01461  */
01462 void cmd_setu(char *new_parms)
01463 {
01464        if (CtdlAccessCheck(ac_logged_in))
01465               return;
01466 
01467        if (num_parms(new_parms) < 3) {
01468               cprintf("%d Usage error.\n", ERROR + ILLEGAL_VALUE);
01469               return;
01470        }
01471        CtdlGetUserLock(&CC->user, CC->curr_user);
01472        CC->user.flags = CC->user.flags & (~US_USER_SET);
01473        CC->user.flags = CC->user.flags | (extract_int(new_parms, 2) & US_USER_SET);
01474        CtdlPutUserLock(&CC->user);
01475        cprintf("%d Ok\n", CIT_OK);
01476 }
01477 
01478 /*
01479  * set last read pointer
01480  */
01481 void cmd_slrp(char *new_ptr)
01482 {
01483        long newlr;
01484        visit vbuf;
01485        visit original_vbuf;
01486 
01487        if (CtdlAccessCheck(ac_logged_in)) {
01488               return;
01489        }
01490 
01491        if (!strncasecmp(new_ptr, "highest", 7)) {
01492               newlr = CC->room.QRhighest;
01493        } else {
01494               newlr = atol(new_ptr);
01495        }
01496 
01497        CtdlGetUserLock(&CC->user, CC->curr_user);
01498 
01499        CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
01500        memcpy(&original_vbuf, &vbuf, sizeof(visit));
01501        vbuf.v_lastseen = newlr;
01502        snprintf(vbuf.v_seen, sizeof vbuf.v_seen, "*:%ld", newlr);
01503 
01504        /* Only rewrite the record if it changed */
01505        if ( (vbuf.v_lastseen != original_vbuf.v_lastseen)
01506           || (strcmp(vbuf.v_seen, original_vbuf.v_seen)) ) {
01507               CtdlSetRelationship(&vbuf, &CC->user, &CC->room);
01508        }
01509 
01510        CtdlPutUserLock(&CC->user);
01511        cprintf("%d %ld\n", CIT_OK, newlr);
01512 }
01513 
01514 
01515 void cmd_seen(char *argbuf) {
01516        long target_msgnum = 0L;
01517        int target_setting = 0;
01518 
01519        if (CtdlAccessCheck(ac_logged_in)) {
01520               return;
01521        }
01522 
01523        if (num_parms(argbuf) != 2) {
01524               cprintf("%d Invalid parameters\n", ERROR + ILLEGAL_VALUE);
01525               return;
01526        }
01527 
01528        target_msgnum = extract_long(argbuf, 0);
01529        target_setting = extract_int(argbuf, 1);
01530 
01531        CtdlSetSeen(&target_msgnum, 1, target_setting,
01532                      ctdlsetseen_seen, NULL, NULL);
01533        cprintf("%d OK\n", CIT_OK);
01534 }
01535 
01536 
01537 void cmd_gtsn(char *argbuf) {
01538        visit vbuf;
01539 
01540        if (CtdlAccessCheck(ac_logged_in)) {
01541               return;
01542        }
01543 
01544        /* Learn about the user and room in question */
01545        CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
01546 
01547        cprintf("%d ", CIT_OK);
01548        client_write(vbuf.v_seen, strlen(vbuf.v_seen));
01549        client_write(HKEY("\n"));
01550 }
01551 
01552 
01553 /*
01554  * API function for cmd_invt_kick() and anything else that needs to
01555  * invite or kick out a user to/from a room.
01556  * 
01557  * Set iuser to the name of the user, and op to 1=invite or 0=kick
01558  */
01559 int CtdlInvtKick(char *iuser, int op) {
01560        struct ctdluser USscratch;
01561        visit vbuf;
01562        char bbb[SIZ];
01563 
01564        if (CtdlGetUser(&USscratch, iuser) != 0) {
01565               return(1);
01566        }
01567 
01568        CtdlGetRelationship(&vbuf, &USscratch, &CC->room);
01569        if (op == 1) {
01570               vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
01571               vbuf.v_flags = vbuf.v_flags | V_ACCESS;
01572        }
01573        if (op == 0) {
01574               vbuf.v_flags = vbuf.v_flags & ~V_ACCESS;
01575               vbuf.v_flags = vbuf.v_flags | V_FORGET | V_LOCKOUT;
01576        }
01577        CtdlSetRelationship(&vbuf, &USscratch, &CC->room);
01578 
01579        /* post a message in Aide> saying what we just did */
01580        snprintf(bbb, sizeof bbb, "%s has been %s \"%s\" by %s.\n",
01581               iuser,
01582               ((op == 1) ? "invited to" : "kicked out of"),
01583               CC->room.QRname,
01584               (CC->logged_in ? CC->user.fullname : "an administrator")
01585        );
01586        CtdlAideMessage(bbb,"User Admin Message");
01587 
01588        return(0);
01589 }
01590 
01591 
01592 /*
01593  * INVT and KICK commands
01594  */
01595 void cmd_invt_kick(char *iuser, int op) {
01596 
01597        /*
01598         * These commands are only allowed by aides, room aides,
01599         * and room namespace owners
01600         */
01601        if (is_room_aide()) {
01602               /* access granted */
01603        } else if ( ((atol(CC->room.QRname) == CC->user.usernum) ) && (CC->user.usernum != 0) ) {
01604               /* access granted */
01605        } else {
01606               /* access denied */
01607               cprintf("%d Higher access or room ownership required.\n",
01608                      ERROR + HIGHER_ACCESS_REQUIRED);
01609               return;
01610        }
01611 
01612        if (!strncasecmp(CC->room.QRname, config.c_baseroom,
01613                       ROOMNAMELEN)) {
01614               cprintf("%d Can't add/remove users from this room.\n",
01615                      ERROR + NOT_HERE);
01616               return;
01617        }
01618 
01619        if (CtdlInvtKick(iuser, op) != 0) {
01620               cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
01621               return;
01622        }
01623 
01624        cprintf("%d %s %s %s.\n",
01625               CIT_OK, iuser,
01626               ((op == 1) ? "invited to" : "kicked out of"),
01627               CC->room.QRname);
01628        return;
01629 }
01630 
01631 void cmd_invt(char *iuser) {cmd_invt_kick(iuser, 1);}
01632 void cmd_kick(char *iuser) {cmd_invt_kick(iuser, 0);}
01633 
01634 /*
01635  * Forget (Zap) the current room (API call)
01636  * Returns 0 on success
01637  */
01638 int CtdlForgetThisRoom(void) {
01639        visit vbuf;
01640 
01641        /* On some systems, Aides are not allowed to forget rooms */
01642        if (is_aide() && (config.c_aide_zap == 0)
01643           && ((CC->room.QRflags & QR_MAILBOX) == 0)  ) {
01644               return(1);
01645        }
01646 
01647        CtdlGetUserLock(&CC->user, CC->curr_user);
01648        CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
01649 
01650        vbuf.v_flags = vbuf.v_flags | V_FORGET;
01651        vbuf.v_flags = vbuf.v_flags & ~V_ACCESS;
01652 
01653        CtdlSetRelationship(&vbuf, &CC->user, &CC->room);
01654        CtdlPutUserLock(&CC->user);
01655 
01656        /* Return to the Lobby, so we don't end up in an undefined room */
01657        CtdlUserGoto(config.c_baseroom, 0, 0, NULL, NULL);
01658        return(0);
01659 
01660 }
01661 
01662 
01663 /*
01664  * forget (Zap) the current room
01665  */
01666 void cmd_forg(char *argbuf)
01667 {
01668 
01669        if (CtdlAccessCheck(ac_logged_in)) {
01670               return;
01671        }
01672 
01673        if (CtdlForgetThisRoom() == 0) {
01674               cprintf("%d Ok\n", CIT_OK);
01675        }
01676        else {
01677               cprintf("%d You may not forget this room.\n", ERROR + NOT_HERE);
01678        }
01679 }
01680 
01681 /*
01682  * Get Next Unregistered User
01683  */
01684 void cmd_gnur(char *argbuf)
01685 {
01686        struct cdbdata *cdbus;
01687        struct ctdluser usbuf;
01688 
01689        if (CtdlAccessCheck(ac_aide)) {
01690               return;
01691        }
01692 
01693        if ((CitControl.MMflags & MM_VALID) == 0) {
01694               cprintf("%d There are no unvalidated users.\n", CIT_OK);
01695               return;
01696        }
01697 
01698        /* There are unvalidated users.  Traverse the user database,
01699         * and return the first user we find that needs validation.
01700         */
01701        cdb_rewind(CDB_USERS);
01702        while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) {
01703               memset(&usbuf, 0, sizeof(struct ctdluser));
01704               memcpy(&usbuf, cdbus->ptr,
01705                      ((cdbus->len > sizeof(struct ctdluser)) ?
01706                      sizeof(struct ctdluser) : cdbus->len));
01707               cdb_free(cdbus);
01708               if ((usbuf.flags & US_NEEDVALID)
01709                   && (usbuf.axlevel > AxDeleted)) {
01710                      cprintf("%d %s\n", MORE_DATA, usbuf.fullname);
01711                      cdb_close_cursor(CDB_USERS);
01712                      return;
01713               }
01714        }
01715 
01716        /* If we get to this point, there are no more unvalidated users.
01717         * Therefore we clear the "users need validation" flag.
01718         */
01719 
01720        begin_critical_section(S_CONTROL);
01721        get_control();
01722        CitControl.MMflags = CitControl.MMflags & (~MM_VALID);
01723        put_control();
01724        end_critical_section(S_CONTROL);
01725        cprintf("%d *** End of registration.\n", CIT_OK);
01726 
01727 
01728 }
01729 
01730 
01731 /*
01732  * validate a user
01733  */
01734 void cmd_vali(char *v_args)
01735 {
01736        char user[128];
01737        int newax;
01738        struct ctdluser userbuf;
01739 
01740        extract_token(user, v_args, 0, '|', sizeof user);
01741        newax = extract_int(v_args, 1);
01742 
01743        if (CtdlAccessCheck(ac_aide) || 
01744            (newax > AxAideU) ||
01745            (newax < AxDeleted)) {
01746               return;
01747        }
01748 
01749        if (CtdlGetUserLock(&userbuf, user) != 0) {
01750               cprintf("%d '%s' not found.\n", ERROR + NO_SUCH_USER, user);
01751               return;
01752        }
01753 
01754        userbuf.axlevel = newax;
01755        userbuf.flags = (userbuf.flags & ~US_NEEDVALID);
01756 
01757        CtdlPutUserLock(&userbuf);
01758 
01759        /* If the access level was set to zero, delete the user */
01760        if (newax == 0) {
01761               if (purge_user(user) == 0) {
01762                      cprintf("%d %s Deleted.\n", CIT_OK, userbuf.fullname);
01763                      return;
01764               }
01765        }
01766        cprintf("%d User '%s' validated.\n", CIT_OK, userbuf.fullname);
01767 }
01768 
01769 
01770 
01771 /* 
01772  *  Traverse the user file...
01773  */
01774 void ForEachUser(void (*CallBack) (struct ctdluser * EachUser, void *out_data),
01775                void *in_data)
01776 {
01777        struct ctdluser usbuf;
01778        struct cdbdata *cdbus;
01779 
01780        cdb_rewind(CDB_USERS);
01781 
01782        while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) {
01783               memset(&usbuf, 0, sizeof(struct ctdluser));
01784               memcpy(&usbuf, cdbus->ptr,
01785                      ((cdbus->len > sizeof(struct ctdluser)) ?
01786                      sizeof(struct ctdluser) : cdbus->len));
01787               cdb_free(cdbus);
01788               (*CallBack) (&usbuf, in_data);
01789        }
01790 }
01791 
01792 
01793 /*
01794  * List one user (this works with cmd_list)
01795  */
01796 void ListThisUser(struct ctdluser *usbuf, void *data)
01797 {
01798        char *searchstring;
01799 
01800        searchstring = (char *)data;
01801        if (bmstrcasestr(usbuf->fullname, searchstring) == NULL) {
01802               return;
01803        }
01804 
01805        if (usbuf->axlevel > AxDeleted) {
01806               if ((CC->user.axlevel >= AxAideU)
01807                   || ((usbuf->flags & US_UNLISTED) == 0)
01808                   || ((CC->internal_pgm))) {
01809                      cprintf("%s|%d|%ld|%ld|%ld|%ld||\n",
01810                             usbuf->fullname,
01811                             usbuf->axlevel,
01812                             usbuf->usernum,
01813                             (long)usbuf->lastcall,
01814                             usbuf->timescalled,
01815                             usbuf->posted);
01816               }
01817        }
01818 }
01819 
01820 /* 
01821  *  List users (searchstring may be empty to list all users)
01822  */
01823 void cmd_list(char *cmdbuf)
01824 {
01825        char searchstring[256];
01826        extract_token(searchstring, cmdbuf, 0, '|', sizeof searchstring);
01827        striplt(searchstring);
01828        cprintf("%d \n", LISTING_FOLLOWS);
01829        ForEachUser(ListThisUser, (void *)searchstring );
01830        cprintf("000\n");
01831 }
01832 
01833 
01834 
01835 
01836 /*
01837  * assorted info we need to check at login
01838  */
01839 void cmd_chek(char *argbuf)
01840 {
01841        int mail = 0;
01842        int regis = 0;
01843        int vali = 0;
01844 
01845        if (CtdlAccessCheck(ac_logged_in)) {
01846               return;
01847        }
01848 
01849        CtdlGetUser(&CC->user, CC->curr_user);    /* no lock is needed here */
01850        if ((REGISCALL != 0) && ((CC->user.flags & US_REGIS) == 0))
01851               regis = 1;
01852 
01853        if (CC->user.axlevel >= AxAideU) {
01854               get_control();
01855               if (CitControl.MMflags & MM_VALID)
01856                      vali = 1;
01857        }
01858 
01859        /* check for mail */
01860        mail = InitialMailCheck();
01861 
01862        cprintf("%d %d|%d|%d|%s|\n", CIT_OK, mail, regis, vali, CC->cs_inet_email);
01863 }
01864 
01865 
01866 /*
01867  * check to see if a user exists
01868  */
01869 void cmd_qusr(char *who)
01870 {
01871        struct ctdluser usbuf;
01872 
01873        if (CtdlGetUser(&usbuf, who) == 0) {
01874               cprintf("%d %s\n", CIT_OK, usbuf.fullname);
01875        } else {
01876               cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
01877        }
01878 }
01879 
01880 
01881 /*
01882  * Administrative Get User Parameters
01883  */
01884 void cmd_agup(char *cmdbuf)
01885 {
01886        struct ctdluser usbuf;
01887        char requested_user[128];
01888 
01889        if (CtdlAccessCheck(ac_aide)) {
01890               return;
01891        }
01892 
01893        extract_token(requested_user, cmdbuf, 0, '|', sizeof requested_user);
01894        if (CtdlGetUser(&usbuf, requested_user) != 0) {
01895               cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
01896               return;
01897        }
01898        cprintf("%d %s|%s|%u|%ld|%ld|%d|%ld|%ld|%d\n",
01899               CIT_OK,
01900               usbuf.fullname,
01901               usbuf.password,
01902               usbuf.flags,
01903               usbuf.timescalled,
01904               usbuf.posted,
01905               (int) usbuf.axlevel,
01906               usbuf.usernum,
01907               (long)usbuf.lastcall,
01908               usbuf.USuserpurge);
01909 }
01910 
01911 
01912 
01913 /*
01914  * Administrative Set User Parameters
01915  */
01916 void cmd_asup(char *cmdbuf)
01917 {
01918        struct ctdluser usbuf;
01919        char requested_user[128];
01920        char notify[SIZ];
01921        int np;
01922        int newax;
01923        int deleted = 0;
01924 
01925        if (CtdlAccessCheck(ac_aide))
01926               return;
01927 
01928        extract_token(requested_user, cmdbuf, 0, '|', sizeof requested_user);
01929        if (CtdlGetUserLock(&usbuf, requested_user) != 0) {
01930               cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
01931               return;
01932        }
01933        np = num_parms(cmdbuf);
01934        if (np > 1)
01935               extract_token(usbuf.password, cmdbuf, 1, '|', sizeof usbuf.password);
01936        if (np > 2)
01937               usbuf.flags = extract_int(cmdbuf, 2);
01938        if (np > 3)
01939               usbuf.timescalled = extract_int(cmdbuf, 3);
01940        if (np > 4)
01941               usbuf.posted = extract_int(cmdbuf, 4);
01942        if (np > 5) {
01943               newax = extract_int(cmdbuf, 5);
01944               if ((newax >= AxDeleted) && (newax <= AxAideU)) {
01945                      usbuf.axlevel = newax;
01946               }
01947        }
01948        if (np > 7) {
01949               usbuf.lastcall = extract_long(cmdbuf, 7);
01950        }
01951        if (np > 8) {
01952               usbuf.USuserpurge = extract_int(cmdbuf, 8);
01953        }
01954        CtdlPutUserLock(&usbuf);
01955        if (usbuf.axlevel == AxDeleted) {
01956               if (purge_user(requested_user) == 0) {
01957                      deleted = 1;
01958               }
01959        }
01960 
01961        if (deleted) {
01962               snprintf(notify, SIZ, 
01963                       "User \"%s\" has been deleted by %s.\n",
01964                       usbuf.fullname,
01965                      (CC->logged_in ? CC->user.fullname : "an administrator")
01966               );
01967               CtdlAideMessage(notify, "User Deletion Message");
01968        }
01969 
01970        cprintf("%d Ok", CIT_OK);
01971        if (deleted)
01972               cprintf(" (%s deleted)", requested_user);
01973        cprintf("\n");
01974 }
01975 
01976 
01977 
01978 /*
01979  * Count the number of new mail messages the user has
01980  */
01981 int NewMailCount()
01982 {
01983        int num_newmsgs = 0;
01984 
01985        num_newmsgs = CC->newmail;
01986        CC->newmail = 0;
01987 
01988        return (num_newmsgs);
01989 }
01990 
01991 
01992 /*
01993  * Count the number of new mail messages the user has
01994  */
01995 int InitialMailCheck()
01996 {
01997        int num_newmsgs = 0;
01998        int a;
01999        char mailboxname[ROOMNAMELEN];
02000        struct ctdlroom mailbox;
02001        visit vbuf;
02002        struct cdbdata *cdbfr;
02003        long *msglist = NULL;
02004        int num_msgs = 0;
02005 
02006        CtdlMailboxName(mailboxname, sizeof mailboxname, &CC->user, MAILROOM);
02007        if (CtdlGetRoom(&mailbox, mailboxname) != 0)
02008               return (0);
02009        CtdlGetRelationship(&vbuf, &CC->user, &mailbox);
02010 
02011        cdbfr = cdb_fetch(CDB_MSGLISTS, &mailbox.QRnumber, sizeof(long));
02012 
02013        if (cdbfr != NULL) {
02014               msglist = malloc(cdbfr->len);
02015               memcpy(msglist, cdbfr->ptr, cdbfr->len);
02016               num_msgs = cdbfr->len / sizeof(long);
02017               cdb_free(cdbfr);
02018        }
02019        if (num_msgs > 0)
02020               for (a = 0; a < num_msgs; ++a) {
02021                      if (msglist[a] > 0L) {
02022                             if (msglist[a] > vbuf.v_lastseen) {
02023                                    ++num_newmsgs;
02024                             }
02025                      }
02026               }
02027        if (msglist != NULL)
02028               free(msglist);
02029 
02030        return (num_newmsgs);
02031 }
02032 
02033 
02034 
02035 /*
02036  * Set the preferred view for the current user/room combination
02037  */
02038 void cmd_view(char *cmdbuf) {
02039        int requested_view;
02040        visit vbuf;
02041 
02042        if (CtdlAccessCheck(ac_logged_in)) {
02043               return;
02044        }
02045 
02046        requested_view = extract_int(cmdbuf, 0);
02047 
02048        CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
02049        vbuf.v_view = requested_view;
02050        CtdlSetRelationship(&vbuf, &CC->user, &CC->room);
02051        
02052        cprintf("%d ok\n", CIT_OK);
02053 }
02054 
02055 
02056 /*
02057  * Rename a user
02058  */
02059 void cmd_renu(char *cmdbuf)
02060 {
02061        int retcode;
02062        char oldname[USERNAME_SIZE];
02063        char newname[USERNAME_SIZE];
02064 
02065        if (CtdlAccessCheck(ac_aide)) {
02066               return;
02067        }
02068 
02069        extract_token(oldname, cmdbuf, 0, '|', sizeof oldname);
02070        extract_token(newname, cmdbuf, 1, '|', sizeof newname);
02071 
02072        retcode = rename_user(oldname, newname);
02073        switch(retcode) {
02074               case RENAMEUSER_OK:
02075                      cprintf("%d '%s' has been renamed to '%s'.\n", CIT_OK, oldname, newname);
02076                      return;
02077               case RENAMEUSER_LOGGED_IN:
02078                      cprintf("%d '%s' is currently logged in and cannot be renamed.\n",
02079                             ERROR + ALREADY_LOGGED_IN , oldname);
02080                      return;
02081               case RENAMEUSER_NOT_FOUND:
02082                      cprintf("%d '%s' does not exist.\n", ERROR + NO_SUCH_USER, oldname);
02083                      return;
02084               case RENAMEUSER_ALREADY_EXISTS:
02085                      cprintf("%d A user named '%s' already exists.\n", ERROR + ALREADY_EXISTS, newname);
02086                      return;
02087        }
02088 
02089        cprintf("%d An unknown error occurred.\n", ERROR);
02090 }
02091 
02092 
02093 
02094 /*****************************************************************************/
02095 /*                      MODULE INITIALIZATION STUFF                          */
02096 /*****************************************************************************/
02097 
02098 
02099 CTDL_MODULE_INIT(user_ops)
02100 {
02101        if (!threading) {
02102               CtdlRegisterProtoHook(cmd_user, "USER", "Submit username for login");
02103               CtdlRegisterProtoHook(cmd_pass, "PASS", "Complete login by submitting a password");
02104               CtdlRegisterProtoHook(cmd_creu, "CREU", "Create User");
02105               CtdlRegisterProtoHook(cmd_setp, "SETP", "Set the password for an account");
02106               CtdlRegisterProtoHook(cmd_getu, "GETU", "Get User parameters");
02107               CtdlRegisterProtoHook(cmd_setu, "SETU", "Set User parameters");
02108               CtdlRegisterProtoHook(cmd_slrp, "SLRP", "Set Last Read Pointer");
02109               CtdlRegisterProtoHook(cmd_invt, "INVT", "Invite a user to a room");
02110               CtdlRegisterProtoHook(cmd_kick, "KICK", "Kick a user out of a room");
02111               CtdlRegisterProtoHook(cmd_forg, "FORG", "Forget a room");
02112               CtdlRegisterProtoHook(cmd_gnur, "GNUR", "Get Next Unregistered User");
02113               CtdlRegisterProtoHook(cmd_vali, "VALI", "Validate new users");
02114               CtdlRegisterProtoHook(cmd_list, "LIST", "List users");
02115               CtdlRegisterProtoHook(cmd_chek, "CHEK", "assorted info we need to check at login");
02116               CtdlRegisterProtoHook(cmd_qusr, "QUSR", "check to see if a user exists");
02117               CtdlRegisterProtoHook(cmd_agup, "AGUP", "Administratively Get User Parameters");
02118               CtdlRegisterProtoHook(cmd_asup, "ASUP", "Administratively Set User Parameters");
02119               CtdlRegisterProtoHook(cmd_seen, "SEEN", "Manipulate seen/unread message flags");
02120               CtdlRegisterProtoHook(cmd_gtsn, "GTSN", "Fetch seen/unread message flags");
02121               CtdlRegisterProtoHook(cmd_view, "VIEW", "Set preferred view for user/room combination");
02122               CtdlRegisterProtoHook(cmd_renu, "RENU", "Rename a user");
02123               CtdlRegisterProtoHook(cmd_newu, "NEWU", "Log in as a new user");
02124        }
02125        /* return our Subversion id for the Log */
02126        return "user_ops";
02127 }