X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fuser_ops.c;h=99543f719c7e26efd640e939faa114eb15204707;hb=9ffea7c3315046ddcea2589656c13da5f5e0c076;hp=dab7f296baed524f125cc5f849672ad6f5805998;hpb=8db8def130c7e0b01dfce85aa2bc207e22188b94;p=citadel.git diff --git a/citadel/user_ops.c b/citadel/user_ops.c index dab7f296b..99543f719 100644 --- a/citadel/user_ops.c +++ b/citadel/user_ops.c @@ -1,7 +1,7 @@ /* * Server functions which perform operations on user objects. * - * Copyright (c) 1987-2018 by the citadel.org team + * Copyright (c) 1987-2019 by the citadel.org team * * This program is open source software; you can redistribute it and/or * modify it under the terms of the GNU General Public License, version 3. @@ -31,6 +31,39 @@ 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 + * (it's just the username converted into lower case) + */ +void makeuserkey(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]); + } +} + /* * CtdlGetUser() retrieve named user into supplied buffer. @@ -40,7 +73,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 +122,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 +158,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); @@ -397,38 +430,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; - - /* 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; - } +void rebuild_ubn_for_user(char *username, void *data) { + struct ctdluser u; - 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 +446,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 */ } @@ -475,15 +481,13 @@ int getuserbyuid(struct ctdluser *usbuf, uid_t number) /* * Back end for cmd_user() and its ilk - * - * NOTE: "authname" should only be used if we are attempting to use the "master user" feature */ -int CtdlLoginExistingUser(char *authname, const char *trythisname) +int CtdlLoginExistingUser(const char *trythisname) { char username[SIZ]; int found_user; - syslog(LOG_DEBUG, "user_ops: CtdlLoginExistingUser(%s, %s)", authname, trythisname); + syslog(LOG_DEBUG, "user_ops: CtdlLoginExistingUser(%s)", trythisname); if ((CC->logged_in)) { return login_already_logged_in; @@ -497,16 +501,6 @@ int CtdlLoginExistingUser(char *authname, const char *trythisname) return login_not_found; } - /* If a "master user" is defined, handle its authentication if specified */ - CC->is_master = 0; - if ( (!IsEmptyStr(CtdlGetConfigStr("c_master_user"))) && - (!IsEmptyStr(CtdlGetConfigStr("c_master_pass"))) && - (authname != NULL) && - (!strcasecmp(authname, CtdlGetConfigStr("c_master_user"))) ) - { - CC->is_master = 1; - } - /* Continue attempting user validation... */ safestrncpy(username, trythisname, sizeof (username)); striplt(username); @@ -712,9 +706,6 @@ void CtdlUserLogout(void) * since it's possible to log in again without reconnecting, we cannot * make that assumption. */ - strcpy(CCC->fake_username, ""); - strcpy(CCC->fake_hostname, ""); - strcpy(CCC->fake_roomname, ""); CCC->logged_in = 0; /* Check to see if the user was deleted while logged in and purge them if necessary */ @@ -725,13 +716,9 @@ void CtdlUserLogout(void) /* Clear out the user record in memory so we don't behave like a ghost */ memset(&CCC->user, 0, sizeof(struct ctdluser)); CCC->curr_user[0] = 0; - CCC->is_master = 0; CCC->cs_inet_email[0] = 0; CCC->cs_inet_other_emails[0] = 0; CCC->cs_inet_fn[0] = 0; - CCC->fake_username[0] = 0; - CCC->fake_hostname[0] = 0; - CCC->fake_roomname[0] = 0; /* Free any output buffers */ unbuffer_output(); @@ -846,10 +833,6 @@ int CtdlTryPassword(const char *password, long len) return pass_wrong_password; } - if (CCC->is_master) { - code = strcmp(password, CtdlGetConfigStr("c_master_pass")); - } - else if (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_HOST) { /* host auth mode */ @@ -935,7 +918,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)) { @@ -1161,52 +1144,49 @@ 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 feu { + char username[USERNAME_SIZE]; + int version; + }; + struct cdbdata *cdbus; + struct ctdluser *usptr; + int i = 0; + struct feu *usernames = NULL; + int num_users = 0; + int num_users_alloc = 0; 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; + if (strlen(usptr->fullname) > 0) { + ++num_users; + if (num_users > num_users_alloc) { + num_users_alloc = ((num_users_alloc == 0) ? 1 : (num_users_alloc * 2)); + usernames = realloc(usernames, num_users_alloc * sizeof(struct feu)); + } + strcpy(usernames[num_users-1].username, usptr->fullname); + usernames[num_users-1].version = usptr->version; + } + } -/* - * 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 (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 + for (i=0; i