-/*
- * Server functions which perform operations on user objects.
- *
- * Copyright (c) 1987-2011 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// Server functions which perform operations on user objects.
+//
+// Copyright (c) 1987-2022 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
#include "support.h"
#include "control.h"
#include "ctdl_module.h"
-
#include "citserver.h"
-
+#include "config.h"
#include "user_ops.h"
#include "internet_addressing.h"
-
-/*
- * USER cmd
- */
-void cmd_user(char *cmdbuf)
-{
+// USER command -- attempt to log in as an existing user
+void cmd_user(char *cmdbuf) {
char username[256];
int a;
- CON_syslog(LOG_DEBUG, "cmd_user(%s)\n", cmdbuf);
extract_token(username, cmdbuf, 0, '|', sizeof username);
- CON_syslog(LOG_DEBUG, "username: %s\n", username);
striplt(username);
- CON_syslog(LOG_DEBUG, "username: %s\n", username);
+ syslog(LOG_DEBUG, "user_ops: cmd_user(%s)", username);
- a = CtdlLoginExistingUser(NULL, username);
+ a = CtdlLoginExistingUser(username);
switch (a) {
case login_already_logged_in:
cprintf("%d Already logged in.\n", ERROR + ALREADY_LOGGED_IN);
"Too many users are already online "
"(maximum is %d)\n",
ERROR + MAX_SESSIONS_EXCEEDED,
- config.c_nodename, config.c_maxsessions);
+ CtdlGetConfigStr("c_nodename"), CtdlGetConfigInt("c_maxsessions"));
return;
case login_ok:
- cprintf("%d Password required for %s\n",
- MORE_DATA, CC->curr_user);
+ cprintf("%d Password required for %s\n", MORE_DATA, CC->curr_user);
return;
case login_not_found:
cprintf("%d %s not found.\n", ERROR + NO_SUCH_USER, username);
}
-void cmd_pass(char *buf)
-{
+// PASS command -- complete logging in as an existing user (used after USER returns MORE_DATA)
+void cmd_pass(char *buf) {
char password[SIZ];
int a;
long len;
}
-/*
- * cmd_newu() - create a new user account and log in as that user
- */
-void cmd_newu(char *cmdbuf)
-{
+// cmd_newu() - create a new user account and log in as that user
+void cmd_newu(char *cmdbuf) {
int a;
- long len;
char username[SIZ];
- if (config.c_auth_mode != AUTHMODE_NATIVE) {
+ if (CtdlGetConfigInt("c_auth_mode") != AUTHMODE_NATIVE) {
cprintf("%d This system does not use native mode authentication.\n",
ERROR + NOT_HERE);
return;
}
- if (config.c_disable_newu) {
- cprintf("%d Self-service user account creation "
- "is disabled on this system.\n", ERROR + NOT_HERE);
+ if (CtdlGetConfigInt("c_disable_newu")) {
+ cprintf("%d Self-service user account creation is disabled on this system.\n", ERROR + NOT_HERE);
return;
}
if (CC->nologin) {
cprintf("%d %s: Too many users are already online (maximum is %d)\n",
ERROR + MAX_SESSIONS_EXCEEDED,
- config.c_nodename, config.c_maxsessions);
+ CtdlGetConfigStr("c_nodename"), CtdlGetConfigInt("c_maxsessions"));
return;
}
extract_token(username, cmdbuf, 0, '|', sizeof username);
strproc(username);
- len = cutuserkey(username);
if (IsEmptyStr(username)) {
cprintf("%d You must supply a user name.\n", ERROR + USERNAME_REQUIRED);
if ((!strcasecmp(username, "bbs")) ||
(!strcasecmp(username, "new")) ||
- (!strcasecmp(username, "."))) {
+ (!strcasecmp(username, "."))
+ ) {
cprintf("%d '%s' is an invalid login name.\n", ERROR + ILLEGAL_VALUE, username);
return;
}
- a = create_user(username, len, 1);
+ a = create_user(username, CREATE_USER_BECOME_USER, NATIVE_AUTH_UID);
if (a == 0) {
logged_in_response();
- } else if (a == ERROR + ALREADY_EXISTS) {
+ }
+ else if (a == ERROR + ALREADY_EXISTS) {
cprintf("%d '%s' already exists.\n",
ERROR + ALREADY_EXISTS, username);
return;
- } else if (a == ERROR + INTERNAL_ERROR) {
+ }
+ else if (a == ERROR + INTERNAL_ERROR) {
cprintf("%d Internal error - user record disappeared?\n",
ERROR + INTERNAL_ERROR);
return;
- } else {
+ }
+ else {
cprintf("%d unknown error\n", ERROR + INTERNAL_ERROR);
}
}
-/*
- * set password - citadel protocol implementation
- */
-void cmd_setp(char *new_pw)
-{
+
+// set password - citadel protocol implementation
+void cmd_setp(char *new_pw) {
if (CtdlAccessCheck(ac_logged_in)) {
return;
}
cprintf("%d Not allowed. Use the 'passwd' command.\n", ERROR + NOT_HERE);
return;
}
- if (CC->is_master) {
- cprintf("%d The master prefix password cannot be changed with this command.\n",
- ERROR + NOT_HERE);
- return;
- }
if (!strcasecmp(new_pw, "GENERATE_RANDOM_PASSWORD")) {
char random_password[17];
}
-/*
- * cmd_creu() - administratively create a new user account (do not log in to it)
- */
-void cmd_creu(char *cmdbuf)
-{
+// cmd_creu() - administratively create a new user account (do not log in to it)
+void cmd_creu(char *cmdbuf) {
int a;
- long len;
char username[SIZ];
char password[SIZ];
struct ctdluser tmp;
cprintf("%d You must supply a user name.\n", ERROR + USERNAME_REQUIRED);
return;
}
- len = cutuserkey(username);
-
extract_token(password, cmdbuf, 1, '|', sizeof password);
- a = create_user(username, len, 0);
+ a = create_user(username, CREATE_USER_DO_NOT_BECOME_USER, NATIVE_AUTH_UID);
if (a == 0) {
if (!IsEmptyStr(password)) {
safestrncpy(tmp.password, password, sizeof(tmp.password));
CtdlPutUserLock(&tmp);
}
- cprintf("%d User '%s' created %s.\n", CIT_OK, username,
- (!IsEmptyStr(password)) ? "and password set" :
- "with no password");
+ cprintf("%d User '%s' created %s.\n", CIT_OK, username, (!IsEmptyStr(password)) ? "and password set" : "with no password");
return;
- } else if (a == ERROR + ALREADY_EXISTS) {
+ }
+ else if (a == ERROR + ALREADY_EXISTS) {
cprintf("%d '%s' already exists.\n", ERROR + ALREADY_EXISTS, username);
return;
- } else if ( (config.c_auth_mode != AUTHMODE_NATIVE) && (a == ERROR + NO_SUCH_USER) ) {
- cprintf("%d User accounts are not created within Citadel in host authentication mode.\n",
- ERROR + NO_SUCH_USER);
+ }
+ else if ( (CtdlGetConfigInt("c_auth_mode") != AUTHMODE_NATIVE) && (a == ERROR + NO_SUCH_USER) ) {
+ cprintf("%d User accounts are not created within Citadel in host authentication mode.\n", ERROR + NO_SUCH_USER);
return;
- } else {
+ }
+ else {
cprintf("%d An error occurred creating the user account.\n", ERROR + INTERNAL_ERROR);
}
}
-
-/*
- * get user parameters
- */
-void cmd_getu(char *cmdbuf)
-{
-
- if (CtdlAccessCheck(ac_logged_in))
+// get user parameters
+void cmd_getu(char *cmdbuf) {
+ if (CtdlAccessCheck(ac_logged_in)) {
return;
+ }
CtdlGetUser(&CC->user, CC->curr_user);
- cprintf("%d 80|24|%d|\n",
- CIT_OK,
- (CC->user.flags & US_USER_SET)
- );
+ cprintf("%d 80|24|%d|\n", CIT_OK, (CC->user.flags & US_USER_SET));
}
-/*
- * set user parameters
- */
-void cmd_setu(char *new_parms)
-{
- if (CtdlAccessCheck(ac_logged_in))
+
+// set user parameters
+void cmd_setu(char *new_parms) {
+ if (CtdlAccessCheck(ac_logged_in)) {
return;
+ }
if (num_parms(new_parms) < 3) {
cprintf("%d Usage error.\n", ERROR + ILLEGAL_VALUE);
cprintf("%d Ok\n", CIT_OK);
}
-/*
- * set last read pointer
- */
-void cmd_slrp(char *new_ptr)
-{
+
+// set last read pointer (marks all messages in the current room as read, up to the specified point)
+void cmd_slrp(char *new_ptr) {
long newlr;
visit vbuf;
visit original_vbuf;
if (!strncasecmp(new_ptr, "highest", 7)) {
newlr = CC->room.QRhighest;
- } else {
+ }
+ else {
newlr = atol(new_ptr);
}
vbuf.v_lastseen = newlr;
snprintf(vbuf.v_seen, sizeof vbuf.v_seen, "*:%ld", newlr);
- /* Only rewrite the record if it changed */
- if ( (vbuf.v_lastseen != original_vbuf.v_lastseen)
- || (strcmp(vbuf.v_seen, original_vbuf.v_seen)) ) {
+ // Only rewrite the record if it changed
+ if ( (vbuf.v_lastseen != original_vbuf.v_lastseen)
+ || (strcmp(vbuf.v_seen, original_vbuf.v_seen))
+ ) {
CtdlSetRelationship(&vbuf, &CC->user, &CC->room);
}
return;
}
- /* Learn about the user and room in question */
+ // Learn about the user and room in question
CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
cprintf("%d ", CIT_OK);
client_write(HKEY("\n"));
}
-/*
- * INVT and KICK commands
- */
+
+// INVT and KICK commands (grant/revoke access to an invitation-only room)
void cmd_invt_kick(char *iuser, int op) {
- /*
- * These commands are only allowed by admins, room admins,
- * and room namespace owners
- */
+ // These commands are only allowed by admins, room admins,
+ // and room namespace owners
if (is_room_aide()) {
- /* access granted */
- } else if ( ((atol(CC->room.QRname) == CC->user.usernum) ) && (CC->user.usernum != 0) ) {
- /* access granted */
- } else {
- /* access denied */
- cprintf("%d Higher access or room ownership required.\n",
- ERROR + HIGHER_ACCESS_REQUIRED);
+ // access granted
+ }
+ else if ( ((atol(CC->room.QRname) == CC->user.usernum) ) && (CC->user.usernum != 0) ) {
+ // access granted
+ }
+ else {
+ // access denied
+ cprintf("%d Higher access or room ownership required.\n", ERROR + HIGHER_ACCESS_REQUIRED);
return;
}
- if (!strncasecmp(CC->room.QRname, config.c_baseroom,
- ROOMNAMELEN)) {
- cprintf("%d Can't add/remove users from this room.\n",
- ERROR + NOT_HERE);
+ if (!strncasecmp(CC->room.QRname, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)) {
+ cprintf("%d Can't add/remove users from this room.\n", ERROR + NOT_HERE);
return;
}
return;
}
-void cmd_invt(char *iuser) {cmd_invt_kick(iuser, 1);}
-void cmd_kick(char *iuser) {cmd_invt_kick(iuser, 0);}
+void cmd_invt(char *iuser) {
+ cmd_invt_kick(iuser, 1);
+}
+
+
+void cmd_kick(char *iuser) {
+ cmd_invt_kick(iuser, 0);
+}
-/*
- * forget (Zap) the current room
- */
-void cmd_forg(char *argbuf)
-{
+
+// forget (Zap) the current room
+void cmd_forg(char *argbuf) {
if (CtdlAccessCheck(ac_logged_in)) {
return;
}
}
-/*
- * Get Next Unregistered User
- */
-void cmd_gnur(char *argbuf)
-{
+
+// Get Next Unregistered User
+void cmd_gnur(char *argbuf) {
struct cdbdata *cdbus;
struct ctdluser usbuf;
return;
}
- if ((CitControl.MMflags & MM_VALID) == 0) {
+ if ((CtdlGetConfigInt("MMflags") & MM_VALID) == 0) {
cprintf("%d There are no unvalidated users.\n", CIT_OK);
return;
}
- /* There are unvalidated users. Traverse the user database,
- * and return the first user we find that needs validation.
- */
+ // There are unvalidated users. Traverse the user database, and return the first user we find that needs validation.
cdb_rewind(CDB_USERS);
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));
+ memcpy(&usbuf, cdbus->ptr, ((cdbus->len > sizeof(struct ctdluser)) ? sizeof(struct ctdluser) : cdbus->len));
cdb_free(cdbus);
- if ((usbuf.flags & US_NEEDVALID)
- && (usbuf.axlevel > AxDeleted)) {
+ if ((usbuf.flags & US_NEEDVALID) && (usbuf.axlevel > AxDeleted)) {
cprintf("%d %s\n", MORE_DATA, usbuf.fullname);
cdb_close_cursor(CDB_USERS);
return;
}
}
- /* If we get to this point, there are no more unvalidated users.
- * Therefore we clear the "users need validation" flag.
- */
-
+ // If we get to this point, there are no more unvalidated users. Therefore we clear the "users need validation" flag.
begin_critical_section(S_CONTROL);
- get_control();
- CitControl.MMflags = CitControl.MMflags & (~MM_VALID);
- put_control();
+ int flags;
+ flags = CtdlGetConfigInt("MMflags");
+ flags = flags & (~MM_VALID);
+ CtdlSetConfigInt("MMflags", flags);
end_critical_section(S_CONTROL);
cprintf("%d *** End of registration.\n", CIT_OK);
-
-
}
-/*
- * validate a user
- */
-void cmd_vali(char *v_args)
-{
+// validate a user
+void cmd_vali(char *v_args) {
char user[128];
int newax;
struct ctdluser userbuf;
extract_token(user, v_args, 0, '|', sizeof user);
newax = extract_int(v_args, 1);
- if (CtdlAccessCheck(ac_aide) ||
- (newax > AxAideU) ||
- (newax < AxDeleted)) {
+ if (CtdlAccessCheck(ac_aide) || (newax > AxAideU) || (newax < AxDeleted)) {
return;
}
CtdlPutUserLock(&userbuf);
- /* If the access level was set to zero, delete the user */
+ // If the access level was set to zero, delete the user
if (newax == 0) {
if (purge_user(user) == 0) {
cprintf("%d %s Deleted.\n", CIT_OK, userbuf.fullname);
cprintf("%d User '%s' validated.\n", CIT_OK, userbuf.fullname);
}
-/*
- * List users (searchstring may be empty to list all users)
- */
-void cmd_list(char *cmdbuf)
-{
+
+// List one user (this works with cmd_list)
+void ListThisUser(char *username, void *data) {
+ char *searchstring;
+ struct ctdluser usbuf;
+
+ if (CtdlGetUser(&usbuf, username) != 0) {
+ return;
+ }
+
+ 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);
+ }
+ }
+}
+
+
+// List users (searchstring may be empty to list all users)
+void cmd_list(char *cmdbuf) {
char searchstring[256];
extract_token(searchstring, cmdbuf, 0, '|', sizeof searchstring);
striplt(searchstring);
}
-
-
-/*
- * assorted info we need to check at login
- */
-void cmd_chek(char *argbuf)
-{
+// assorted info we need to check at login
+void cmd_chek(char *argbuf) {
int mail = 0;
int regis = 0;
int vali = 0;
return;
}
- CtdlGetUser(&CC->user, CC->curr_user); /* no lock is needed here */
- if ((REGISCALL != 0) && ((CC->user.flags & US_REGIS) == 0))
+ CtdlGetUser(&CC->user, CC->curr_user); // no lock is needed here
+ if ((REGISCALL != 0) && ((CC->user.flags & US_REGIS) == 0)) {
regis = 1;
+ }
if (CC->user.axlevel >= AxAideU) {
- get_control();
- if (CitControl.MMflags & MM_VALID)
+ if (CtdlGetConfigInt("MMflags") & MM_VALID) {
vali = 1;
+ }
}
- /* check for mail */
- mail = InitialMailCheck();
-
+ mail = InitialMailCheck(); // check for mail
cprintf("%d %d|%d|%d|%s|\n", CIT_OK, mail, regis, vali, CC->cs_inet_email);
}
-/*
- * check to see if a user exists
- */
-void cmd_qusr(char *who)
-{
+// check to see if a user exists
+void cmd_qusr(char *who) {
struct ctdluser usbuf;
if (CtdlGetUser(&usbuf, who) == 0) {
cprintf("%d %s\n", CIT_OK, usbuf.fullname);
- } else {
+ }
+ else {
cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
}
}
-/*
- * Administrative Get User Parameters
- */
-void cmd_agup(char *cmdbuf)
-{
+// Administrative Get User Parameters
+void cmd_agup(char *cmdbuf) {
struct ctdluser usbuf;
char requested_user[128];
}
-
-/*
- * Administrative Set User Parameters
- */
-void cmd_asup(char *cmdbuf)
-{
+// Administrative Set User Parameters
+void cmd_asup(char *cmdbuf) {
struct ctdluser usbuf;
char requested_user[128];
char notify[SIZ];
if (deleted) {
snprintf(notify, SIZ,
- "User \"%s\" has been deleted by %s.\n",
- usbuf.fullname,
- (CC->logged_in ? CC->user.fullname : "an administrator")
+ "User \"%s\" has been deleted by %s.\n",
+ usbuf.fullname, (CC->logged_in ? CC->user.fullname : "an administrator")
);
CtdlAideMessage(notify, "User Deletion Message");
}
cprintf("%d Ok", CIT_OK);
- if (deleted)
+ if (deleted) {
cprintf(" (%s deleted)", requested_user);
+ }
cprintf("\n");
}
-/*
- * Citadel protocol command to do the same
- */
+// Citadel protocol command to do the same
void cmd_isme(char *argbuf) {
char addr[256];
}
-/*
- * Set the preferred view for the current user/room combination
- */
+// Retrieve all Internet email addresses/aliases for the specified user
+void cmd_agea(char *cmdbuf) {
+ struct ctdluser usbuf;
+ char requested_user[128];
+ int i, num_e;
+ char e[512];
+
+ if (CtdlAccessCheck(ac_aide)) {
+ return;
+ }
+
+ extract_token(requested_user, cmdbuf, 0, '|', sizeof requested_user);
+ if (CtdlGetUser(&usbuf, requested_user) != 0) {
+ cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
+ return;
+ }
+ cprintf("%d internet email addresses for %s\n", LISTING_FOLLOWS, usbuf.fullname);
+ num_e = num_tokens(usbuf.emailaddrs, '|');
+ for (i=0; i<num_e; ++i) {
+ extract_token(e, usbuf.emailaddrs, i, '|', sizeof e);
+ cprintf("%s\n", e);
+ }
+ cprintf("000\n");
+}
+
+
+// Set the Internet email addresses/aliases for the specified user
+void cmd_asea(char *cmdbuf) {
+ struct ctdluser usbuf;
+ char requested_user[128];
+ char buf[SIZ];
+ char whodat[64];
+ char new_emailaddrs[512] = { 0 } ;
+
+ if (CtdlAccessCheck(ac_aide)) return;
+
+ extract_token(requested_user, cmdbuf, 0, '|', sizeof requested_user);
+ if (CtdlGetUser(&usbuf, requested_user) != 0) {
+ cprintf("%d No such user.\n", ERROR + NO_SUCH_USER);
+ return;
+ }
+
+ cprintf("%d Ok\n", SEND_LISTING);
+ while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
+ if (IsEmptyStr(buf)) {
+ syslog(LOG_ERR, "user_ops: address <%s> is empty - not using", buf);
+ }
+ else if ((strlen(new_emailaddrs) + strlen(buf) + 2) > sizeof(new_emailaddrs)) {
+ syslog(LOG_ERR, "user_ops: address <%s> does not fit in buffer - not using", buf);
+ }
+ else if (!IsDirectory(buf, 0)) {
+ syslog(LOG_ERR, "user_ops: address <%s> is not in one of our domains - not using", buf);
+ }
+ else if ( (CtdlDirectoryLookup(whodat, buf, sizeof whodat) == 0) && (CtdlUserCmp(whodat, requested_user)) ) {
+ syslog(LOG_ERR, "user_ops: address <%s> already belongs to <%s> - not using", buf, whodat);
+ }
+ else {
+ syslog(LOG_DEBUG, "user_ops: address <%s> validated", buf);
+ if (!IsEmptyStr(new_emailaddrs)) {
+ strcat(new_emailaddrs, "|");
+ }
+ strcat(new_emailaddrs, buf);
+ }
+ }
+
+ CtdlSetEmailAddressesForUser(requested_user, new_emailaddrs);
+}
+
+
+// Set the preferred view for the current user/room combination
void cmd_view(char *cmdbuf) {
int requested_view;
visit vbuf;
}
-/*
- * Rename a user
- */
-void cmd_renu(char *cmdbuf)
-{
+// Rename a user
+void cmd_renu(char *cmdbuf) {
int retcode;
char oldname[USERNAME_SIZE];
char newname[USERNAME_SIZE];
return;
case RENAMEUSER_LOGGED_IN:
cprintf("%d '%s' is currently logged in and cannot be renamed.\n",
- ERROR + ALREADY_LOGGED_IN , oldname);
+ ERROR + ALREADY_LOGGED_IN , oldname
+ );
return;
case RENAMEUSER_NOT_FOUND:
cprintf("%d '%s' does not exist.\n", ERROR + NO_SUCH_USER, oldname);
}
-
-void cmd_quit(char *argbuf)
-{
+void cmd_quit(char *argbuf) {
cprintf("%d Goodbye.\n", CIT_OK);
CC->kill_me = KILLME_CLIENT_LOGGED_OUT;
}
-void cmd_lout(char *argbuf)
-{
+void cmd_lout(char *argbuf) {
if (CC->logged_in)
CtdlUserLogout();
cprintf("%d logged out.\n", CIT_OK);
CtdlRegisterProtoHook(cmd_qusr, "QUSR", "check to see if a user exists");
CtdlRegisterProtoHook(cmd_agup, "AGUP", "Administratively Get User Parameters");
CtdlRegisterProtoHook(cmd_asup, "ASUP", "Administratively Set User Parameters");
+ CtdlRegisterProtoHook(cmd_agea, "AGEA", "Administratively Get Email Addresses");
+ CtdlRegisterProtoHook(cmd_asea, "ASEA", "Administratively Set Email Addresses");
CtdlRegisterProtoHook(cmd_seen, "SEEN", "Manipulate seen/unread message flags");
CtdlRegisterProtoHook(cmd_gtsn, "GTSN", "Fetch seen/unread message flags");
CtdlRegisterProtoHook(cmd_view, "VIEW", "Set preferred view for user/room combination");