X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fuser_ops.c;h=9a39b06b6754b7b4c940fbd0e06acf0959476411;hb=6d624cc4161ba0ce4892a7e7aaee7fd89dffa245;hp=7f6ed1c15309ba3d8f7bde5efefbc77132968480;hpb=58c77aea1dda7b206b900bafb9278237456ef737;p=citadel.git diff --git a/citadel/user_ops.c b/citadel/user_ops.c index 7f6ed1c15..9a39b06b6 100644 --- a/citadel/user_ops.c +++ b/citadel/user_ops.c @@ -32,6 +32,43 @@ int chkpwd_write_pipe[2]; int chkpwd_read_pipe[2]; +/* + * Trim a string down to the maximum username size and return the new length + */ +long cutusername(char *username) { + long len; + len = strlen(username); + if (len >= USERNAME_SIZE) + { + syslog(LOG_INFO, "Username too long: %s", username); + len = USERNAME_SIZE - 1; + username[len]='\0'; + } + return len; +} + + +/* + * makeuserkey() - convert a username into the format used as a database key + * (Key format is the username with all non-alphanumeric characters removed, and converted to lower case.) + */ +void makeuserkey(char *key, const char *username, long len) { + int i; + int keylen = 0; + + if (len >= USERNAME_SIZE) { + syslog(LOG_INFO, "Username too long: %s", username); + len = USERNAME_SIZE - 1; + } + for (i=0; i<=len; ++i) { + if (isalnum((username[i]))) { + key[keylen++] = tolower(username[i]); + } + } + key[keylen++] = 0; +} + + /* * CtdlGetUser() retrieve named user into supplied buffer. * returns 0 on success @@ -40,7 +77,7 @@ int CtdlGetUser(struct ctdluser *usbuf, char *name) { char usernamekey[USERNAME_SIZE]; struct cdbdata *cdbus; - long len = cutuserkey(name); + long len = cutusername(name); if (usbuf != NULL) { memset(usbuf, 0, sizeof(struct ctdluser)); @@ -89,7 +126,7 @@ void CtdlPutUser(struct ctdluser *usbuf) { char usernamekey[USERNAME_SIZE]; - makeuserkey(usernamekey, usbuf->fullname, cutuserkey(usbuf->fullname)); + makeuserkey(usernamekey, usbuf->fullname, cutusername(usbuf->fullname)); usbuf->version = REV_LEVEL; cdb_store(CDB_USERS, usernamekey, strlen(usernamekey), usbuf, sizeof(struct ctdluser)); } @@ -125,8 +162,8 @@ int rename_user(char *oldname, char *newname) { char newnamekey[USERNAME_SIZE]; /* Create the database keys... */ - makeuserkey(oldnamekey, oldname, cutuserkey(oldname)); - makeuserkey(newnamekey, newname, cutuserkey(newname)); + makeuserkey(oldnamekey, oldname, cutusername(oldname)); + makeuserkey(newnamekey, newname, cutusername(newname)); /* Lock up and get going */ begin_critical_section(S_USERS); @@ -145,10 +182,8 @@ int rename_user(char *oldname, char *newname) { if (CtdlGetUser(&usbuf, oldname) != 0) { retcode = RENAMEUSER_NOT_FOUND; } - else { /* Sanity checks succeeded. Now rename the user. */ - if (usbuf.usernum == 0) - { + if (usbuf.usernum == 0) { syslog(LOG_DEBUG, "user_ops: can not rename user \"Citadel\"."); retcode = RENAMEUSER_NOT_FOUND; } else { @@ -168,6 +203,57 @@ int rename_user(char *oldname, char *newname) { } +/* + * Convert a username into the format used as a database key prior to version 928 + * This only gets called by reindex_user_928() + */ +void makeuserkey_pre928(char *key, const char *username, long len) { + int i; + + if (len >= USERNAME_SIZE) { + syslog(LOG_INFO, "Username too long: %s", username); + len = USERNAME_SIZE - 1; + } + for (i=0; i<=len; ++i) { + key[i] = tolower(username[i]); + } +} + + +/* + * Read a user record using the pre-v928 index format, and write it back using the v928-and-higher index format. + * This ONLY gets called during an upgrade from version <928 to version >=928. + */ +void reindex_user_928(char *username, void *out_data) { + + char oldkey[USERNAME_SIZE]; + char newkey[USERNAME_SIZE]; + struct cdbdata *cdbus; + long len = cutusername(username); + struct ctdluser usbuf; + + makeuserkey_pre928(oldkey, username, len); + makeuserkey(newkey, username, len); + + syslog(LOG_DEBUG, "user_ops: reindex_user_928: %s <%s> --> <%s>", username, oldkey, newkey); + + // Fetch the user record using the old index format + cdbus = cdb_fetch(CDB_USERS, oldkey, strlen(oldkey)); + if (cdbus == NULL) { + syslog(LOG_INFO, "user_ops: <%s> not found, were they already reindexed?", username); + return; + } + memcpy(&usbuf, cdbus->ptr, ((cdbus->len > sizeof(struct ctdluser)) ? sizeof(struct ctdluser) : cdbus->len)); + cdb_free(cdbus); + + // delete the old record + cdb_delete(CDB_USERS, oldkey, strlen(oldkey)); + + // write the new record + cdb_store(CDB_USERS, newkey, strlen(newkey), &usbuf, sizeof(struct ctdluser)); +} + + /* * Index-generating function used by Ctdl[Get|Set]Relationship */ @@ -176,7 +262,6 @@ int GenerateRelationshipIndex(char *IndexBuf, long RoomGen, long UserID) { - struct { long iRoomID; long iRoomGen; @@ -214,10 +299,7 @@ void put_visit(visit *newvisit) /* * Define a relationship between a user and a room */ -void CtdlSetRelationship(visit *newvisit, - struct ctdluser *rel_user, - struct ctdlroom *rel_room) -{ +void CtdlSetRelationship(visit *newvisit, struct ctdluser *rel_user, struct ctdlroom *rel_room) { /* We don't use these in Citadel because they're implicit by the * index, but they must be present if the database is exported. */ @@ -232,10 +314,7 @@ void CtdlSetRelationship(visit *newvisit, /* * Locate a relationship between a user and a room */ -void CtdlGetRelationship(visit *vbuf, - struct ctdluser *rel_user, - struct ctdlroom *rel_room) -{ +void CtdlGetRelationship(visit *vbuf, struct ctdluser *rel_user, struct ctdlroom *rel_room) { char IndexBuf[32]; int IndexLen; struct cdbdata *cdbvisit; @@ -397,38 +476,12 @@ int CtdlGetUserByNumber(struct ctdluser *usbuf, long number) /* * 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; +void rebuild_ubn_for_user(char *username, void *data) { + struct ctdluser u; - /* 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) { - syslog(LOG_DEBUG, "user_ops: rebuilding usersbynumber index %10ld : %s", 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); + syslog(LOG_DEBUG, "user_ops: rebuilding usersbynumber index for %s", username); + if (CtdlGetUser(&u, username) == 0) { + cdb_store(CDB_USERSBYNUMBER, &(u.usernum), sizeof(long), u.fullname, strlen(u.fullname)+1); } } @@ -439,7 +492,6 @@ void rebuild_ubn_for_user(struct ctdluser *usbuf, void *data) { 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 */ } @@ -912,7 +964,7 @@ int purge_user(char pname[]) struct ctdluser usbuf; char usernamekey[USERNAME_SIZE]; - makeuserkey(usernamekey, pname, cutuserkey(pname)); + makeuserkey(usernamekey, pname, cutusername(pname)); /* If the name is empty we can't find them in the DB any way so just return */ if (IsEmptyStr(pname)) { @@ -1138,52 +1190,44 @@ int CtdlForgetThisRoom(void) { /* - * Traverse the user file... + * Traverse the user file and perform a callback for each user record. + * (New improved version that runs in two phases so that callbacks can perform writes without having a r/o cursor open) */ -void ForEachUser(void (*CallBack) (struct ctdluser * EachUser, void *out_data), - void *in_data) +void ForEachUser(void (*CallBack) (char *, void *out_data), void *in_data) { - struct ctdluser usbuf; struct cdbdata *cdbus; + struct ctdluser *usptr; + + struct feu { + struct feu *next; + char username[USERNAME_SIZE]; + }; + struct feu *usernames = NULL; + struct feu *f = NULL; cdb_rewind(CDB_USERS); + // Phase 1 : load list of usernames 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); - (*CallBack) (&usbuf, in_data); - } -} - + usptr = (struct ctdluser *) cdbus->ptr; -/* - * List one user (this works with cmd_list) - */ -void ListThisUser(struct ctdluser *usbuf, void *data) -{ - char *searchstring; - - searchstring = (char *)data; - if (bmstrcasestr(usbuf->fullname, searchstring) == NULL) { - return; + if (strlen(usptr->fullname) > 0) { + f = malloc(sizeof(struct feu)); + f->next = usernames; + strncpy(f->username, usptr->fullname, USERNAME_SIZE); + usernames = f; + } } - if (usbuf->axlevel > AxDeleted) { - if ((CC->user.axlevel >= AxAideU) - || ((usbuf->flags & US_UNLISTED) == 0) - || ((CC->internal_pgm))) { - cprintf("%s|%d|%ld|%ld|%ld|%ld||\n", - usbuf->fullname, - usbuf->axlevel, - usbuf->usernum, - (long)usbuf->lastcall, - usbuf->timescalled, - usbuf->posted); - } + // Phase 2 : perform the callback for each username + while (usernames != NULL) { + (*CallBack) (usernames->username, in_data); + f = usernames; + usernames = usernames->next; + free(f); } + + free(usernames); }