/* ARISA - User account manipulation functions * Copyright (C) 2003, 2004 Carl Ritson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "arisa.h" #include "user.h" priv_text_t priv_text[] = { {PRIV_PACK_ADD, "PACK_ADD"}, {PRIV_PACK_DEL, "PACK_DEL"}, {PRIV_PACK_MOD, "PACK_MOD"}, {PRIV_SEND_ADD, "SEND_ADD"}, {PRIV_SEND_DEL, "SEND_DEL"}, {PRIV_SEND_MOD, "SEND_MOD"}, {PRIV_PACKLIST_SEND, "PACKLIST_SEND"}, {PRIV_PACKLIST_SCAN, "PACKLIST_SCAN"}, {PRIV_PACKLIST_MOD, "PACKLIST_MOD"}, {PRIV_ALL_PACKLISTS, "ALL_PACKLISTS"}, {PRIV_PACKLISTS, "PACKLISTS"}, {PRIV_QUEUES, "QUEUES"}, {PRIV_POOLS, "POOLS"}, {PRIV_INTERFACES, "INTERFACES"}, {PRIV_FILES, "FILES"}, {PRIV_FILE_MOVE, "FILE_MOVE"}, {PRIV_FILE_DEL, "FILE_DEL"}, {PRIV_DIR_ADD, "DIR_ADD"}, {PRIV_DIR_DEL, "DIR_DEL"}, {PRIV_SELF_MOD, "SELF_MOD"}, {PRIV_USERS, "USERS"}, {PRIV_UPLOAD, "UPLOAD"}, {PRIV_DOWNLOAD, "DOWNLOAD"}, {PRIV_LOG, "LOG"}, {PRIV_PARTY_LINE, "PARTY_LINE"}, {PRIV_MESSAGE, "MESSAGE"}, {PRIV_NETWORKS, "NETWORKS"}, {PRIV_SETTINGS, "SETTINGS"}, {PRIV_SHUTDOWN, "SHUTDOWN"}, {PRIV_SOCKET, "SOCKET"}, {PRIV_MAX, NULL} }; user_t *alloc_user(const char *username) { user_t *u = xalloc(sizeof(user_t)); LOCK_INIT(&u->lock); u->deleted = 0; if(username != NULL) u->username = xstrdup(username); else u->username = NULL; u->password = NULL; u->hosts = NULL; u->no_hosts = 0; u->dirs = NULL; u->no_dirs = 0; u->packlists = NULL; u->no_packlists = 0; u->no_permitted_logons = 1; u->privs = NULL; u->uprivs = PRIVS_EMPTY; if(u->username != NULL) { user_set_privs(u,PRIVS_EMPTY); } u->last_logon = 0; return u; } void free_user(user_t *u) { LOCK_FREE(&(u->lock)); if(u->username != NULL) xfree(u->username); if(u->password != NULL) xfree(u->password); if(u->hosts != NULL) xfree(u->hosts); if(u->dirs != NULL) xfree(u->dirs); if(u->packlists != NULL) xfree(u->packlists); if(u->privs != NULL) xfree(u->privs); xfree(u); } int user_add(user_t *u) { int i,ret = -1; LOCK(global); LOCK(u); for(i = 0; i < global->no_users; ++i) { LOCK(global->users[i]); if(strcmp(global->users[i]->username,u->username) == 0 && global->users[i]->deleted == 0) { LOGP(L_ERR, "Error, attempted to add duplicate user %s.", global->users[i]->username); break; } UNLOCK(global->users[i]); } if(i == global->no_users) { LOGP(L_INF,"Added User %s",u->username); PTRARR_ADD(&global->users,&global->no_users,u); validity_insert(u); ret = 0; } UNLOCK(u); UNLOCK(global); if(ret == 0) se_notify_user_add(u); return ret; } user_t *user_find(const char *name) { user_t *u = NULL; int i; LOCK(global); for(i = 0; i < global->no_users && u == NULL; ++i) { LOCK(global->users[i]); if(global->users[i]->deleted == 0 && strcmp(global->users[i]->username,name) == 0) { u = global->users[i]; validity_insert(u); } UNLOCK(global->users[i]); } UNLOCK(global); return u; } int user_del(user_t *u) { interface_t *intf; int i,j; LOCK(global); LOCK(u); u->deleted = xtime(); validity_delete(u); UNLOCK(u); for(i = 0; i < global->no_interfaces; ++i) { intf = global->interfaces[i]; LOCK(intf); if(intf->type == INTERFACE_CHAT) { for(j = 0; j < intf->chat.no_chats; ++j) { LOCK(intf->chat.chats[j]); if(intf->chat.chats[j]->type == CHAT_ADMIN && intf->chat.chats[j]->admin.user == u) { intf->chat.chats[j]->state = STATE_DELETED; intf->chat.chats[j]->admin.user = NULL; } UNLOCK(intf->chat.chats[j]); } } /* else if(intf->type == INTERFACE_RECV) { for(j = 0; j < intf->recv.no_uploads; ++j) { LOCK(intf->recv.uploads[j]); if(intf->recv.uploads[j]->user == u) { intf->recv.uploads[j]->state = STATE_DELETED; intf->recv.uploads[j]->user = NULL; } UNLOCK(intf->recv.uploads[j]); } } */ UNLOCK(intf); } for(i = 0; i < global->no_admins; ++i) { LOCK(global->admins[i]); if(global->admins[i]->admin.user == u) global->admins[i]->state = STATE_DELETED; UNLOCK(global->admins[i]); } UNLOCK(global); return 0; } void user_purge(const time_t now) { user_t **old = NULL; int i,j,deleted,no_old = 0; //D("User Purge Begins"); LOCK(global); for(i = 0, deleted = 0; i < global->no_users; ++i) { LOCK(global->users[i]); if(IS_PURGE_TIME(global->users[i]->deleted,now)) deleted++; UNLOCK(global->users[i]); } if(deleted != 0) { old = global->users; no_old = global->no_users; PTRARR_ALLOC(&(global->users),&(global->no_users), no_old - deleted); for(i = 0, j = 0; i < no_old; ++i) { LOCK(old[i]); if(!IS_PURGE_TIME(old[i]->deleted,now)) { global->users[j++] = old[i]; UNLOCK(old[i]); old[i] = NULL; } else UNLOCK(old[i]); } } UNLOCK(global); if(old != NULL) { for(i = 0; i < no_old; ++i) { if(old[i] != NULL) free_user(old[i]); } xfree(old); } //D("User Purge Ends"); } int user_set_password(user_t *u, const char *password) { char buffer[128]; char pwdhash[36]; LOCK(u); snprintf(buffer,sizeof(buffer),"%s%s",u->username,password); strtomd5(pwdhash,sizeof(pwdhash),buffer); memset(buffer,0,sizeof(buffer)); if(u->password != NULL) xfree(u->password); u->password = xstrdup(pwdhash); UNLOCK(u); return 0; } int user_check_password(user_t *u, const char *password) { char buffer[128]; char pwdhash[36]; int ret = 0; LOCK(u); if(u->password != NULL) { snprintf(buffer,sizeof(buffer),"%s%s",u->username,password); strtomd5(pwdhash,sizeof(pwdhash),buffer); memset(buffer,0,sizeof(buffer)); if(strcmp(u->password,pwdhash) == 0) ret = 1; } UNLOCK(u); return ret; } int user_valid(user_t *u) { int i; if(u == NULL) return 0; if(validity_test(u)) return 1; LOCK(global); for(i = 0; i < global->no_users; ++i) { if(global->users[i] == u) { LOCK(u); i = u->deleted; if(u->deleted == 0) validity_insert(u); UNLOCK(u); UNLOCK(global); if(i == 0) // u->deleted == 0 return 1; else return 0; } } UNLOCK(global); return 0; } int user_rename(user_t *u, const char *name) { int i, ret = 0; if(u == NULL || name == NULL) return -1; LOCK(global); for(i = 0; i < global->no_users && ret == 0; ++i) { LOCK(global->users[i]); if(global->users[i]->deleted == 0 && strcmp(global->users[i]->username,name) == 0) ret = -1; UNLOCK(global->users[i]); } if(ret == 0) { LOCK(u); if(u->username != NULL) xfree(u->username); u->username = xstrdup(name); UNLOCK(u); } UNLOCK(global); return ret; } /** Settings Data **/ static setting_t user_data[] = { {"permitted-logons", ST_INT, OFFSETOF(user_t,no_permitted_logons), 0,"0",NULL,NULL}, {NULL} }; int user_apply_setting(user_t *u, const char *name, const char *value) { value_t *v = value_string(name,value); int ret; LOCK(u); ret = apply_setting(user_data,u,v); UNLOCK(u); xfree(v); return ret; } int user_read_settings(user_t *u, pqueue_t *out) { int ret; LOCK(u); ret = read_settings(user_data,u,out); UNLOCK(u); return ret; }