/* ARISA - Admin Interface - User(s) Menu * Copyright (C) 2003 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 */ static int is_user_new(user_t *u) { int i; LOCK(global); for(i = 0; i < global->no_users; ++i) { if(global->users[i] == u) { UNLOCK(global); return 0; } } UNLOCK(global); return 1; } /** User Menu Commands **/ MENU_HELPER(cmd_users_helper) { int i,j; LOCK(global); for(j = 0; args[1][j] != '\0'; ++j) { if(args[1][j] == '?') break; } for(i = 0; i < global->no_users; ++i) { LOCK(global->users[i]); if(global->users[i]->deleted == 0 && (j == 0 || strncmp(global->users[i]->username,args[1],j) == 0)) admin_msg(ac,"%s",global->users[i]->username); UNLOCK(global->users[i]); } UNLOCK(global); } MENU_CMD(cmd_user_delete) { user_t *u = (user_t *)ins->data; LOCK(u); if(no_args == 1) { admin_cmsg(ac,"Are you %%9really%%n sure you want to delete the user account \"%s\"?",u->username); admin_msg(ac,"If so run '%s %s' instead.",args[0],u->username); UNLOCK(u); } else if(strcasecmp(args[1],u->username) == 0) { admin_msg(ac,"User %s Deleted",u->username); UNLOCK(u); user_del(u); return CHAIN_CMD(cmd_exit); } return 0; } MENU_CMD(cmd_user_save) { user_t *u = (user_t *)ins->data; int ret; if(is_user_new(u)) { ret = user_add(u); if(ret == 0) { ins->free = NULL; admin_msg(ac,"Successfully Saved."); } else admin_msg(ac,"Save Failed."); } else admin_msg(ac,"User is already saved."); return 0; } MENU_CMD(cmd_user_info) { user_t *u = (user_t *)ins->data; char buffer[128]; int i,j; LOCK(u); admin_msg(ac,"-- User %s --",u->username); admin_msg(ac,"Last Logon: %s", u->last_logon == 0 ? "Unknown" : timestr(u->last_logon,buffer,sizeof(buffer))); admin_msg(ac,"Has Privileges:"); for(i = 0,j = 0; priv_text[i].text != NULL; ++i) { if(PRIV_ISSET(u,priv_text[i].priv)) { if((j + strlen(priv_text[i].text)) >= 80) { admin_msg(ac,"%s",buffer); j = 0; } j += IMIN( snprintf(buffer + j,sizeof(buffer)-j, " %s",priv_text[i].text), sizeof(buffer)-j-1); } } if(j != 0) admin_msg(ac,"%s",buffer); UNLOCK(u); return 0; } MENU_CMD(cmd_user_hosts) { user_t *u = (user_t *)ins->data; int ret; LOCK(u); ret = cmd_strarr(ac,&u->hosts,&u->no_hosts,args,no_args); UNLOCK(u); return ret; } MENU_CMD(cmd_user_dirs) { user_t *u = (user_t *)ins->data; struct stat sdata; int i,ret,sret; LOCK(u); ret = cmd_strarr(ac,&u->dirs,&u->no_dirs,args,no_args); for(i = 0; i < u->no_dirs; ++i) { sret = stat(u->dirs[i],&sdata); // hmm, this might block if(sret != 0 || !S_ISDIR(sdata.st_mode)) admin_msg(ac,"Warning Directory %d (\"%s\") is not valid", i+1,u->dirs[i]); } UNLOCK(u); return ret; } MENU_CMD(cmd_user_settings) { user_t *u = (user_t *)ins->data; if(no_args == 1) { pqueue_t settings; pqueue_init(&settings,0); user_read_settings(u,&settings); output_settings(ac,"-- User Settings for %s --", u->username,&settings); } else if(no_args >= 3) { if(user_apply_setting(u,args[1],args[2]) == -1) admin_msg(ac,"Invalid setting: %s",args[1]); } else admin_msg(ac,"%s [ ]",args[0]); return 0; } MENU_CMD(cmd_user_grant_revoke) { user_t *u = (user_t *)ins->data; int i,j; if(no_args == 1) admin_msg(ac,"%s ",args[0]); else { if(strchr(args[1],'?') != NULL) { for(j = 0; args[1][j] != '\0'; ++j) { if(args[1][j] == '?') break; } for(i = 0; priv_text[i].text != NULL; ++i) { if(strncasecmp(priv_text[i].text,args[1],j) == 0) admin_msg(ac,"%s",priv_text[i].text); } } else { for(j = 1; j < no_args; ++j) { for(i = 0; priv_text[i].text != NULL; ++i) { if(strcasecmp(priv_text[i].text,args[j]) == 0) break; } if(priv_text[i].text != NULL) { LOCK(u); if(tolower(args[0][0]) == 'g') PRIV_SET(u,priv_text[i].priv); else /* tolower(args[0][0]) == 'r' */ PRIV_UNSET(u,priv_text[i].priv); UNLOCK(u); } else admin_msg(ac,"Invalid Privilege Name: %s",args[j]); } } } return 0; } MENU_CMD(cmd_user_password) { user_t *u = (user_t *)ins->data; if(no_args >= 3) { if(strcmp(args[1],args[2]) == 0) user_set_password(u,args[1]); else admin_msg(ac,"Passwords do not match"); } else admin_msg(ac,"%s ",args[0]); return 0; } #if 0 MENU_CMD(cmd_user_uploads) { interface_t *intf; user_t *u = (user_t *)ins->data; pqueue_t il; int i,j; if(no_args == 1) { time_t now = xtime(); pqueue_init(&il,0); LOCK(u); admin_msg(ac,"-- Uploads for %s --",u->username); UNLOCK(u); LOCK(global); for(i = 0; i < global->no_interfaces; ++i) { LOCK(global->interfaces[i]); if(global->interfaces[i]->deleted == 0 && global->interfaces[i]->type == INTERFACE_RECV) pqueue_push_back(&il,global->interfaces[i]); UNLOCK(global->interfaces[i]); } UNLOCK(global); if(pqueue_length(&il) == 0) admin_msg(ac,"None"); while((intf = pqueue_pop_front(&il)) != NULL) { LOCK(intf); for(i = 0; i < intf->recv.no_uploads; ++i) { LOCK(intf->recv.uploads[i]); if(intf->recv.uploads[i]->user == u) { UNLOCK(intf->recv.uploads[i]); cmd_interface_display_upload(ac, intf->recv.uploads[i], now); } else UNLOCK(intf->recv.uploads[i]); } UNLOCK(intf); } } else if(tolower(args[1][0]) == 'c' && no_args == 3) { // close pqueue_init(&il,0); LOCK(global); for(i = 0; i < global->no_interfaces; ++i) { LOCK(global->interfaces[i]); if(global->interfaces[i]->deleted == 0 && global->interfaces[i]->type == INTERFACE_RECV) pqueue_push_back(&il,global->interfaces[i]); UNLOCK(global->interfaces[i]); } UNLOCK(global); j = 0; while((intf = pqueue_pop_front(&il)) != NULL) { LOCK(intf); for(i = 0; i < intf->recv.no_uploads; ++i) { LOCK(intf->recv.uploads[i]); if(intf->recv.uploads[i]->user == u && (send_matchs(intf->recv.uploads[i], args[2],NULL, no_args >= 4 ? args[3] : NULL, NULL,NULL) || send_matchs(intf->recv.uploads[i], args[2],NULL,NULL, no_args >= 4 ? args[3] : NULL, NULL))) { intf->recv.uploads[i]->state = STATE_DELETED; } UNLOCK(intf->recv.uploads[i]); } UNLOCK(intf); } admin_msg(ac,"Closed %d Matching Uploads",j); } else admin_msg(ac,"%s [close []]",args[0]); return 0; } #endif #if 0 MENU_CMD(cmd_user_upload_dir) { user_t *u = (user_t *)ins->data; if(no_args == 1) { LOCK(u); admin_msg(ac,"upload-dir: %s", u->upload_dir != NULL ? u->upload_dir : "Not Set"); UNLOCK(u); } else { struct stat sbuf; int ret = stat(args[1],&sbuf); if(strcmp(args[1],"-") == 0) { LOCK(u); if(u->upload_dir != NULL) xfree(u->upload_dir); u->upload_dir = NULL; } else if(ret == 0 && S_ISDIR(sbuf.st_mode)) { LOCK(u); if(u->upload_dir != NULL) xfree(u->upload_dir); u->upload_dir = xstrdup(args[1]); UNLOCK(u); } else admin_msg(ac,"Invalid Directory: %s",args[1]); } return 0; } #endif MENU_CMD(cmd_user_packlists) { user_t *u = (user_t *)ins->data; packlist_t *p,**access = NULL; int i,no_access = 0; if(no_args == 1) { LOCK(u); admin_msg(ac,"-- Packlist Access for %s --",u->username); if(u->packlists != NULL) { no_access = u->no_packlists; access = xalloc(sizeof(packlist_t *)*no_access); memcpy(access,u->packlists,sizeof(packlist_t *)*no_access); } UNLOCK(u); if(access != NULL) { for(i = 0; i < no_access; ++i) { LOCK(access[i]); admin_msg(ac,"% 2d: %s",i+1,access[i]->name); UNLOCK(access[i]); } xfree(access); } else admin_msg(ac,"Empty"); } else if(tolower(args[1][0]) == 'a') { if(no_args >= 3) { p = packlist_find(args[2]); if(p != NULL) { LOCK(u); PTRARR_ADD(&u->packlists,&u->no_packlists,p); UNLOCK(u); LOCK(p); if(p->deleted != 0) { UNLOCK(p); LOCK(u); PTRARR_DEL(&u->packlists, &u->no_packlists,p); UNLOCK(u); } else UNLOCK(p); } else admin_msg(ac,"Invalid Packlist: %s",args[2]); } else admin_msg(ac,"%s add ",args[0]); } else if(tolower(args[1][0]) == 'd') { if(no_args >= 3) { i = atoi(args[2]); LOCK(u); if(i > 0 && i <= u->no_packlists) PTRARR_DEL(&u->packlists,&u->no_packlists, u->packlists[i-1]); else admin_msg(ac,"Invalid Access Entry: %d",i); UNLOCK(u); } else admin_msg(ac,"%s del ",args[0]); } else if(tolower(args[1][0]) == 'w') { LOCK(u); if(u->packlists != NULL) xfree(u->packlists); u->packlists = NULL; u->no_packlists = 0; UNLOCK(u); } else admin_msg(ac,"%s [ [...]]",args[0]); return 0; } /** User Menu Structure **/ static const cmd_t user_menu[] = { {"delete", cmd_user_delete, 0,1,1,0, PRIV_TO_MASK(PRIV_USERS), NULL}, {"dirs", cmd_user_dirs, 0,3,1,0, PRIV_TO_MASK(PRIV_USERS), NULL}, {"grant", cmd_user_grant_revoke, 0,-1,1,0, PRIV_TO_MASK(PRIV_USERS), NULL}, {"hosts", cmd_user_hosts, 0,3,1,0, PRIVS_EMPTY, NULL}, {"info", cmd_user_info, 0,0,0,0, PRIVS_EMPTY, NULL}, {"packlists", cmd_user_packlists, 0,2,1,0, PRIV_TO_MASK(PRIV_USERS), NULL}, {"password", cmd_user_password, 0,2,0,0, PRIVS_EMPTY, NULL}, {"revoke", cmd_user_grant_revoke, 0,-1,1,0, PRIV_TO_MASK(PRIV_USERS), NULL}, {"save", cmd_user_save, 0,0,1,0, PRIV_TO_MASK(PRIV_USERS), NULL}, {"settings", cmd_user_settings, 0,3,1,0, PRIV_TO_MASK(PRIV_USERS), NULL}, // {"uploads", cmd_user_uploads, 0,3,0,0, // PRIV_TO_MASK(PRIV_UPLOAD), NULL}, // {"upload-dir", cmd_user_upload_dir, 0,1,1,0, // PRIV_TO_MASK(PRIV_USERS), NULL}, {NULL} }; /** User Menu Entry **/ MENU_CHECK(cmd_user_check) { user_t *u = (user_t *)ins->data; int ret = 0; LOCK(u); if(u->deleted != 0) { admin_msg(ac,"User %s, Deleted.",u->username); ret = -1; } UNLOCK(u); return ret; } MENU_CMD(cmd_user_entry) { user_t *u; if(ins->prompt != NULL && ins->free_prompt) xfree(ins->prompt); ins->prompt = xstrdup(args[1]); ins->free_prompt= 1; ins->check = cmd_user_check; u = user_find(args[1]); if(u == NULL) { LOCK(ac->user); if(PRIV_ISSET(ac->user,PRIV_USERS)) { u = alloc_user(args[1]); ins->free = (void (*)(void *)) free_user; admin_msg(ac,"New User: %s",args[1]); } else admin_msg(ac,"Insufficient Privileges"); UNLOCK(ac->user); } if(u != NULL) { ins->data = u; return 0; } else return -1; } /** Users Menu Commands **/ MENU_CMD(cmd_users_logons) { if(no_args == 1) return CHAIN_CMD(cmd_whoison); else if(tolower(args[1][0]) == 'c' && no_args >= 3) { // close user_t *u = NULL; int i,j; if(no_args >= 4) { u = user_find(args[3]); if(u == NULL) { admin_msg(ac,"Invalid User: %s",args[3]); return 0; } } LOCK(global); for(i = 0, j = 0; i < global->no_admins; ++i) { LOCK(global->admins[i]); if(irc_hostmask_match(global->admins[i]->host,args[2]) && (u == NULL || global->admins[i]->admin.user == u)) { global->admins[i]->state = STATE_DELETED; j++; } UNLOCK(global->admins[i]); } UNLOCK(global); admin_msg(ac,"Closed %d Matching Admin Sessions",j); } else admin_msg(ac,"%s [close []]",args[0]); return 0; } /** Users Menu Structure **/ static const cmd_t users_menu[] = { {"logons", cmd_users_logons, 0,3,1,0, PRIVS_EMPTY, NULL}, {NULL} }; MENU_CMD(cmd_self_entry) { char buffer[64]; char *nargs[2]; LOCK(ac->user); xstrncpy(buffer,ac->user->username,sizeof(buffer)); UNLOCK(ac->user); nargs[0] = "self"; nargs[1] = buffer; return CHAIN_CMD_ARGS(cmd_user_entry,nargs,2); } static void register_users_menu(void) { menu_t *us_menu, *u_menu, *s_menu; us_menu = menu_from_cmds( "users", 0, 0, 0, 0, PRIV_TO_MASK(PRIV_USERS), NULL, NULL, (cmd_t *)users_menu); u_menu = menu_from_cmds( "user", 1, 1, 1, 0, PRIVS_EMPTY, cmd_user_entry, cmd_users_helper, (cmd_t *)user_menu); s_menu = menu_from_cmds( "self", 0, 0, 0, 0, PRIV_TO_MASK(PRIV_SELF_MOD), cmd_self_entry, NULL, (cmd_t *)user_menu); menu_add(us_menu,u_menu); menu_add(main_menu_root,us_menu); menu_add(main_menu_root,s_menu); menu_deref(u_menu); menu_deref(us_menu); menu_deref(s_menu); }