/*
* Server functions which perform operations on user objects.
*
- * Copyright (c) 1987-2019 by the citadel.org team
+ * Copyright (c) 1987-2020 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.
int chkpwd_write_pipe[2];
int chkpwd_read_pipe[2];
+
/*
- * Trim a string down to the maximum username size and return the new length
+ * makeuserkey() - convert a username into the format used as a database key
+ * "key" must be a buffer of at least USERNAME_SIZE
+ * (Key format is the username with all non-alphanumeric characters removed, and converted to lower case.)
*/
-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';
+void makeuserkey(char *key, const char *username) {
+ int i;
+ int keylen = 0;
+
+ if (IsEmptyStr(username)) {
+ key[0] = 0;
+ return;
}
- return len;
+
+ int len = strlen(username);
+ for (i=0; ((i<=len) && (i<USERNAME_SIZE-1)); ++i) {
+ if (isalnum((username[i]))) {
+ key[keylen++] = tolower(username[i]);
+ }
+ }
+ key[keylen++] = 0;
}
/*
- * makeuserkey() - convert a username into the format used as a database key
- * (it's just the username converted into lower case)
+ * Compare two usernames to see if they are the same user after being keyed for the database
+ * Usage is identical to strcmp()
*/
-void makeuserkey(char *key, const char *username, long len) {
- int i;
+int CtdlUserCmp(char *s1, char *s2) {
+ char k1[USERNAME_SIZE];
+ char k2[USERNAME_SIZE];
- 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]);
- }
+ makeuserkey(k1, s1);
+ makeuserkey(k2, s2);
+ return(strcmp(k1,k2));
}
{
char usernamekey[USERNAME_SIZE];
struct cdbdata *cdbus;
- long len = cutusername(name);
if (usbuf != NULL) {
memset(usbuf, 0, sizeof(struct ctdluser));
}
- makeuserkey(usernamekey, name, len);
+ makeuserkey(usernamekey, name);
cdbus = cdb_fetch(CDB_USERS, usernamekey, strlen(usernamekey));
if (cdbus == NULL) { /* user not found */
{
char usernamekey[USERNAME_SIZE];
- makeuserkey(usernamekey, usbuf->fullname, cutusername(usbuf->fullname));
+ makeuserkey(usernamekey, usbuf->fullname);
usbuf->version = REV_LEVEL;
cdb_store(CDB_USERS, usernamekey, strlen(usernamekey), usbuf, sizeof(struct ctdluser));
}
char newnamekey[USERNAME_SIZE];
/* Create the database keys... */
- makeuserkey(oldnamekey, oldname, cutusername(oldname));
- makeuserkey(newnamekey, newname, cutusername(newname));
+ makeuserkey(oldnamekey, oldname);
+ makeuserkey(newnamekey, newname);
/* Lock up and get going */
begin_critical_section(S_USERS);
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 {
}
+/*
+ * 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) {
+ int i;
+
+ int len = strlen(username);
+
+ 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;
+ struct ctdluser usbuf;
+
+ makeuserkey_pre928(oldkey, username);
+ makeuserkey(newkey, username);
+
+ 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
*/
long RoomGen,
long UserID)
{
-
struct {
long iRoomID;
long iRoomGen;
/*
* 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.
*/
/*
* 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;
else {
/* native auth mode */
- recptypes *valid = NULL;
+ struct recptypes *valid = NULL;
/* First, try to log in as if the supplied name is a display name */
found_user = CtdlGetUser(&CC->user, username);
AutoGenerateEmailAddressForUser(&CC->user);
}
+ /* Populate the user principal identity, which is consistent and never aliased */
+ strcpy(CC->cs_principal_id, "");
+ makeuserkey(CC->cs_principal_id, CC->user.fullname);
+ strcat(CC->cs_principal_id, "@");
+ strcat(CC->cs_principal_id, CtdlGetConfigStr("c_fqdn"));
+
/*
* Populate cs_inet_email and cs_inet_other_emails with valid email addresses from the user record
*/
struct ctdluser usbuf;
char usernamekey[USERNAME_SIZE];
- makeuserkey(usernamekey, pname, cutusername(pname));
+ makeuserkey(usernamekey, pname);
/* If the name is empty we can't find them in the DB any way so just return */
if (IsEmptyStr(pname)) {
*/
void ForEachUser(void (*CallBack) (char *, void *out_data), void *in_data)
{
+ struct cdbdata *cdbus;
+ struct ctdluser *usptr;
+
struct feu {
+ struct feu *next;
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;
+ struct feu *ufirst = NULL;
+ struct feu *ulast = NULL;
+ struct feu *f = NULL;
cdb_rewind(CDB_USERS);
- // Phase 1 : load list of usernames
+ // Phase 1 : build a linked list of all our user account names
while (cdbus = cdb_next_item(CDB_USERS), cdbus != NULL) {
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));
+ f = malloc(sizeof(struct feu));
+ f->next = NULL;
+ strncpy(f->username, usptr->fullname, USERNAME_SIZE);
+
+ if (ufirst == NULL) {
+ ufirst = f;
+ ulast = f;
+ }
+ else {
+ ulast->next = f;
+ ulast = f;
}
- strcpy(usernames[num_users-1].username, usptr->fullname);
- usernames[num_users-1].version = usptr->version;
}
}
- // Phase 2 : perform the callback for each username
- for (i=0; i<num_users; ++i) {
- syslog(LOG_DEBUG, "user_ops: %3d %3d %s", i, usernames[i].version, usernames[i].username); // FIXME
- if (usernames[i].version < 927) {
- // FIXME we have to reindex this record
- }
- (*CallBack) (usernames[i].username, in_data);
+ // Phase 2 : perform the callback for each user while de-allocating the list
+ while (ufirst != NULL) {
+ (*CallBack) (ufirst->username, in_data);
+ f = ufirst;
+ ufirst = ufirst->next;
+ free(f);
}
-
- free(usernames);
}