/* config.c */ /* Copyright 2005 Aris Adamantiadis This file is part of the SSH Library The SSH Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The SSH Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the SSH Library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "libconfig.h" #include #include #include #include #include "server.h" /* shortvar is "port" in "port 22" */ int port=22; char *dsa=NULL; char *rsa=NULL; list *groups; list *users; struct dir *root_dir=NULL; /* users is a list of users. The key of this list is the user name. the data of the list is a list of groups. both data & key from this list is the group name */ struct group *current_group=NULL; char *current_group_name; int add_user(char *user){ list *groups_from_user; // list *the_user; //printf("add_user(%s)\n",user); if(!list_find(current_group->users,user)){ current_group->users=list_add(current_group->users,user,strdup(user)); } groups_from_user=list_find(users,user); if(!groups_from_user){ // the user isn't registered yet groups_from_user=list_add(NULL,current_group_name,current_group_name); users=list_add(users,user,groups_from_user); } else { // add the group name to the list of groups the user is bound to. if(!list_find(groups_from_user,current_group_name)) // don't add it if it is already set list_set(users,user,list_add(groups_from_user,current_group_name,current_group_name)); } return 0; } int add_group(char *group){ struct group *grp=list_find(groups,group); list *usr; if(!grp){ printf("no such group %s\n",group); return -1; } usr=grp->users; while(usr){ add_user(usr->key); usr=usr->next; } return 0; } int group_callback(const char *shortvar, const char *var, const char *arguments, const char *value, lc_flags_t flags, void *extra){ switch(flags){ case LC_FLAGS_SECTIONSTART: //printf("new group %s\n",arguments); if(current_group){ printf("can't include a section into a section\n"); return LC_CBRET_ERROR; } if(list_find(groups,arguments)){ printf("group %s defined twice\n",arguments); return LC_CBRET_ERROR; } current_group=malloc(sizeof(struct group)); memset(current_group,0,sizeof(struct group)); groups=list_add(groups,arguments,current_group); current_group_name=strdup(arguments); break; case LC_FLAGS_SECTIONEND: //printf("end of group\n\n"); current_group=NULL; break; default: //printf("%s - %s\n", shortvar, value); if(!strcasecmp(shortvar,"user")){ char *ptr; char *user=(char *)value; do{ ptr=strchr(user,','); if(ptr){ *ptr=0; ++ptr; } while(*user==' ') ++user; add_user(user); user=ptr; } while (user); } if(!strcasecmp(shortvar,"group")){ char *ptr; char *group=(char *)value; do{ ptr=strchr(group,','); if(ptr){ *ptr=0; ++ptr; } while(*group==' ') ++group; add_group(group); group=ptr; } while (group); } if(!strcasecmp(shortvar,"uid")){ current_group->uid=strdup(value); } if(!strcasecmp(shortvar,"gid")){ current_group->gid=strdup(value); } if(!strcasecmp(shortvar,"chroot")){ current_group->chroot=strdup(value); } if(!strcasecmp(shortvar,"nopassword")) current_group->nopassword=1; } return LC_CBRET_OKAY; } struct dir *create_directory(const char *directory); struct dir *current_dir=NULL; int append_groups(list **plist, const char *groups){ char *begin=strdup(groups); char *ptr; char *grp=begin; do{ ptr=strchr(grp,','); if(ptr){ *ptr=0; ++ptr; } while(*grp==' ') ++grp; if(!list_find(*plist,grp)) *plist=list_add(*plist,grp,strdup(grp)); grp=ptr; } while (grp); return 0; } int dir_callback(const char *shortvar, const char *var, const char *arguments, const char *value, lc_flags_t flags, void *extra){ switch(flags){ case LC_FLAGS_SECTIONSTART: if(current_dir){ printf("Cannot define a directory into a directory !\n"); return LC_CBRET_ERROR; } current_dir=create_directory(arguments); break; case LC_FLAGS_SECTIONEND: current_dir=NULL; break; default: if(!strcasecmp(shortvar,"list")) append_groups(¤t_dir->List,value); if(!strcasecmp(shortvar,"read")) append_groups(¤t_dir->Read,value); if(!strcasecmp(shortvar,"write")) append_groups(¤t_dir->Write,value); // printf("%s - %s\n",shortvar, value); } return LC_CBRET_OKAY; } void list_config(){ list *ptr=groups; list *user; printf("listing groups\n"); while(ptr){ printf("group %s\n",ptr->key); user=((struct group *)ptr->data)->users; while(user){ printf(" user %s\n",user->key); user=user->next; } ptr=ptr->next; } printf("listing users\n"); user=users; while(user){ printf("user %s\n",user->key); ptr=user->data; while(ptr){ printf(" group %s\n",ptr->key); ptr=ptr->next; } user=user->next; } } char **cut_directory(const char *dir){ char *tmp=strdup(dir); char *ptr; char *ret[128]; char **answer; int i=0; while(tmp && *tmp && i<128){ while(*tmp=='/') ++tmp; ptr=strchr(tmp,'/'); if(ptr){ *ptr=0; ++ptr; } ret[i]=strdup(tmp); tmp=ptr; i++; } answer=malloc((i+1)*sizeof(char *)); memcpy(answer,ret,sizeof(char *)*i); answer[i]=NULL; return answer; } struct dir *dir_new(){ struct dir *dir=malloc(sizeof(struct dir)); memset(dir,0,sizeof(*dir)); return dir; } /* it doesn't really create the directory. it makes the tree to the directory * and returns a link to the last node */ struct dir *create_directory(const char *directory){ char **tokens=cut_directory(directory); int i=0; struct dir *dir,*ptr; if(!root_dir){ root_dir=dir_new(); root_dir->name=""; } dir=root_dir; for(i=0;tokens[i];++i){ ptr=list_find(dir->subdir,tokens[i]); if(!ptr){ ptr=dir_new(); ptr->name=strdup(tokens[i]); dir->subdir=list_add(dir->subdir,tokens[i],ptr); } dir=ptr; } for(i=0;tokens[i];++i) free(tokens[i]); free(tokens); return dir; } int parse_config(char *file){ int r; printf("Parsing configuration file %s\n",file); lc_register_var("Port",LC_VAR_INT,&port,' '); lc_register_var("Hostkeyrsa",LC_VAR_STRING,&rsa,' '); lc_register_var("Hostkeydsa",LC_VAR_STRING,&dsa,' '); // lc_register_var("group", LC_VAR_SECTION, NULL, 0); r=lc_register_callback("group",0,LC_VAR_NONE,group_callback,NULL); r=lc_register_callback("group.user",0,LC_VAR_UNKNOWN,group_callback,NULL); r=lc_register_callback("group.uid",0,LC_VAR_UNKNOWN,group_callback,NULL); r=lc_register_callback("group.chroot",0,LC_VAR_UNKNOWN,group_callback,NULL); r=lc_register_callback("group.group",0,LC_VAR_UNKNOWN,group_callback,NULL); r=lc_register_callback("group.nopassword",0,LC_VAR_NONE,group_callback,NULL); // lc_register_var("dir", LC_VAR_SECTION, NULL, 0); r=lc_register_callback("dir",0,LC_VAR_NONE,dir_callback,NULL); r=lc_register_callback("dir.list",0,LC_VAR_UNKNOWN,dir_callback,NULL); r=lc_register_callback("dir.read",0,LC_VAR_UNKNOWN,dir_callback,NULL); r=lc_register_callback("dir.write",0,LC_VAR_UNKNOWN,dir_callback,NULL); r=lc_process_file("sftp",file,LC_CONF_APACHE); if(r<0) printf("lc_process_file=%d,%s\n",r,lc_geterrstr()); lc_cleanup(); //list_config(); return r<0; } list *find_groups(char *user){ return list_find(users,user); } char *user_chroot(char *user){ char *c_grp; list *group=find_groups(user); struct group *grp; while(group){ c_grp=group->key; grp=list_find(groups,c_grp); if(grp->chroot) return grp->chroot; group=group->next; } return NULL; } char *user_uid(char *user){ char *c_grp; list *group=find_groups(user); struct group *grp; while(group){ c_grp=group->key; grp=list_find(groups,c_grp); if(grp->uid) return grp->uid; group=group->next; } return NULL; } /* 0 if it's not specified. 1 if the user doesn't need a password */ int user_nopassword(char *user){ char *c_grp; list *group=find_groups(user); struct group *grp; if(!group) return 0; //user doesn't exist while(group){ c_grp=group->key; grp=list_find(groups,c_grp); if(grp->nopassword) return 1; group=group->next; } return 0; }