#pragma implementation #include #include #include #include #include "groupware.h" #include "groupware.m" #include #include #include #include #include #include static HELP_FILE help_groupware ("groupware","groupware"); MODULE_DEFINE_VERSION(groupware); static const char *keymenu=NULL; static const char K_GROUPWARE[]="groupware"; static const char K_GROUP[]="group"; static const char K_BASEDIR[]="basedir"; static const char K_OPERMODE[]="opermode"; static const char K_MAXSHARES[]="maxshares"; static const char K_MAXSHAREUSERS[]="maxshareusers"; static const char K_ALLOWEDUSERS[]="allowedusers"; /* Return the base directory where all groupware shares are created */ static const char *groupware_basedir() { return linuxconf_getval (K_GROUPWARE,K_BASEDIR,"/groupware"); } /* Return the group owning the files in the special shares */ static const char *groupware_group() { return linuxconf_getval(K_GROUPWARE,K_GROUP,"groupware"); } /* Return the list of users and groups allowed to create shares */ static int groupware_allowedusers(SSTRINGS &tb) { const char *line = linuxconf_getval (K_GROUPWARE,K_ALLOWEDUSERS,""); return str_splitline (line,' ',tb); } /* Return the maximum allowed number of groupware shares */ static int groupware_maxshares() { return linuxconf_getvalnum (K_GROUPWARE,K_MAXSHARES,100); } /* A user is allowed to create that many groupware shares */ static int groupware_maxshareusers() { return linuxconf_getvalnum (K_GROUPWARE,K_MAXSHAREUSERS,2); } #define OPERMODE_NONE 0 #define OPERMODE_COADMIN 1 #define OPERMODE_ENDUSERS 2 /* Return the operation mode of the module (OPERMODE_xxx) */ static int groupware_opermode () { return linuxconf_getvalnum(K_GROUPWARE,K_OPERMODE,0); } /* Check if a group exist. If not, allow the admin to create it. Return -1 if the group does not exist (and was not created). */ static int groupware_creategroup (const char *gname) { int ret = 0; struct group *g = getgrnam (gname); if (g == NULL && perm_rootaccess (MSG_U(P_CREATINGGROUP,"to create groups"))){ SSTRING intro; intro.setfromf (MSG_U(I_CREATINGGROUP ,"The group %s does not exist.\n" "Do you want to create it ?") ,gname); ret = -1; if (xconf_yesno (MSG_U(T_CREATINGGROUP,"Creating group") ,intro.get() ,help_groupware)==MENU_YES){ ret = groups_add (gname); } } return ret; } static char tbuser[10]; /* Configure the module settings. */ static void groupware_settings() { if (perm_rootaccess(MSG_U(P_EDITSETTINGS,"configure the groupware service"))){ DIALOG dia; SSTRING group (groupware_group()); SSTRING basedir (groupware_basedir()); SSTRINGS users; groupware_allowedusers(users); int maxshares = groupware_maxshares(); int maxshareusers = groupware_maxshareusers(); char opermode = groupware_opermode(); dia.newf_title (MSG_U(I_DETAILS,"Details"),1,"",MSG_R(I_DETAILS)); dia.newf_str (MSG_U(F_GROUP,"Files owned by group"),group); dia.last_noempty(); dia.newf_str (MSG_U(F_BASEDIR,"Base directory for shares"),basedir); dia.last_noempty(); static const char *tbmode[]={ MSG_U(I_DISABLED,"Disabled"), MSG_U(I_COADMIN,"Co-administrator"), MSG_U(I_ENDUSERS,"End-users"), NULL }; dia.newf_chkm (MSG_U(F_OPERMODE,"Operation mode"),opermode,tbmode); dia.newf_num (MSG_U(F_MAXSHARES,"Max. groupware shares"),maxshares); dia.newf_num (MSG_U(F_MAXSHAREUSERS,"Max. shares per user"),maxshareusers); dia.newf_title (MSG_U(I_ALLOWEDUSERS,"Allowed users/Groups"),1,"" ,MSG_R(I_ALLOWEDUSERS)); for (int i=0; i<2; i++) users.add (new SSTRING); if (dialog_registrymode()){ while (users.getnb() < 5) users.add (new SSTRING); } for (int i=0; iset_registry_key (tbuser+i); } int enduserfield = dia.getnb(); PRIVATE_MESSAGE morelines; dia.new_button (MSG_U(B_MORELINES,"More lines") ,MSG_U(I_MORELINES,"Add more users or groups"),morelines); int nof = 0; while (1){ MENU_STATUS code = dia.edit (MSG_U(M_GROUPSETTING,"Groupware settings"),"",help_groupware ,nof); if (code == MENU_ESCAPE || code == MENU_CANCEL){ break; }else if (code == MENU_MESSAGE){ if (dialog_testmessage(morelines)){ for (int i=0; i<1; i++){ SSTRING *s = new SSTRING; users.add (s); dia.set_nextfield (enduserfield++); dia.newf_str ("",*s); } } }else if (groupware_creategroup(group.get())==-1){ nof = 0; }else{ SSTRING errors; for (int i=0; iget(); if (*s == '@'){ s++; if (getgrnam (s)==NULL){ errors.appendf (MSG_R(E_NOGROUP),s); } }else if (*s != '\0'){ if (getpwnam (s)==NULL){ errors.appendf (MSG_R(E_NOUSER),s); } } } if (errors.is_filled()){ xconf_error ("%s",errors.get()); }else{ linuxconf_replace (K_GROUPWARE,K_GROUP,group); linuxconf_replace (K_GROUPWARE,K_BASEDIR,basedir); linuxconf_replace (K_GROUPWARE,K_OPERMODE,opermode); linuxconf_replace (K_GROUPWARE,K_MAXSHARES,maxshares); linuxconf_replace (K_GROUPWARE,K_MAXSHAREUSERS,maxshareusers); SSTRING tmp; for (int i=0; iis_filled()) tmp.appendf (" %s",s->get()); } linuxconf_replace (K_GROUPWARE,K_ALLOWEDUSERS,tmp); linuxconf_save(); break; } } } } } /* Get one setting from a samba share */ static const char *groupware_getreg (const char *suffix, const char *share) { SSTRING key; key.setfromf ("samba.share_%s.%s",suffix,share); return master_registry.get (key.get()); } static int groupware_getregnum (const char *suffix, const char *share) { int ret = 0; const char *val = groupware_getreg (suffix,share); if (val != NULL) ret = atoi(val); return ret; } /* Split a line containing users and groups. The users may be separated either by space or comma. */ static int groupware_splitusers (const char *s, SSTRINGS &tb) { char tmp[strlen(s)+1]; strcpy (tmp,s); char *pt; // Turn all commas to spaces while ((pt=strchr(tmp,','))!=NULL) *pt = ' '; return str_splitline (tmp,' ',tb); } /* Get an entry from the vregistry which is a list of users and groups */ static int groupware_getregu (const char *suffix, const char *share, SSTRINGS &tb) { int ret = 0; const char *u = groupware_getreg (suffix,share); if (u != NULL) ret = groupware_splitusers (u,tb); return ret; } /* Set one setting of a samba share */ static void groupware_setreg ( const char *suffix, const char *share, const char *value) { SSTRING key; key.setfromf ("samba.share_%s.%s",suffix,share); master_registry.set (key.get(),value); } static void groupware_setreg ( const char *suffix, const char *share, const SSTRING &value) { groupware_setreg (suffix,share,value.get()); } static void groupware_setreg ( const char *suffix, const char *share, bool value) { groupware_setreg (suffix,share,value ? "1" : "0"); } static void groupware_setregu ( const char *suffix, const char *share, const SSTRINGS &values) // List of users and groups { SSTRING list; bool one = false; for (int i=0; iget(); if (v[0] != '\0'){ list.appendf (one ? ",%s" : "%s",v); one = true; } } groupware_setreg (suffix,share,list); } static PRIVILEGE p_shares ("groupware" ,P_MSG_U(T_PRIVGROUP,"Groupware/shares administrator") ,P_MSG_U(T_PMISC,"9-Miscellaneous")); /* Check if all users or groups exist. Write error messages in errors. */ static void groupware_validusers(const SSTRINGS &users, SSTRING &errors) { for (int i=0; iget(); if (u[0] == '@'){ u++; if (getgrnam (u)==NULL){ errors.appendf (MSG_U(E_NOGROUP,"Group %s does not exist\n"),u); } }else if (u[0] != '\0'){ if (getpwnam (u)==NULL){ errors.appendf (MSG_U(E_NOUSER,"User %s does not exist\n"),u); } } } } /* Extract the list of groupware shares */ static int groupware_getshares(SSTRINGS &tb) { int ret = 0; const char *basedir = groupware_basedir(); int lenbasedir = strlen(basedir); master_registry.start_session(); SSTRINGS all; master_registry.getlist ("samba.shares",all); for (int i=0; iget(); const char *path = groupware_getreg ("path",s); if (strncmp(path,basedir,lenbasedir)==0 && path[lenbasedir] == '/'){ tb.add (new SSTRING(s)); ret ++; } } master_registry.end_session(); return ret; } /* Edit one special share */ static void groupware_edit( const char *share, const char *user) { SSTRING name(share); SSTRING admin; // User who can managed the share and can always // write to it. It may be a list of users SSTRINGS readers; // Users only allowed to read SSTRINGS writers; // Users allowed to write if the share is writeable SSTRING comment; char enabled=1,writable=1; DIALOG dia; dia.newf_title (MSG_R(I_DETAILS),1,"",MSG_R(I_DETAILS)); dia.newf_str (MSG_U(F_SHARENAME,"Share name"),name); if (share != NULL){ dia.set_lastreadonly(); master_registry.start_session(); comment.setfrom (groupware_getreg("comment",share)); enabled = groupware_getregnum("available",share); writable = groupware_getregnum("writable",share); SSTRINGS users; groupware_getregu("validusers",share,users); groupware_getregu("readlist",share,readers); SSTRINGS admins; groupware_getregu("writelist",share,admins); master_registry.end_session(); /* #Specification: share administrator The admin is always the first member in user list */ for (int i=0; iget()); } /* #Specification: share logic / readers and writers We setup the share this way: All members are in the valid user list. Some of those users are also in the "read list". So they can only read even if the share is writable. Other users are in the write list. They can always write. They are also the administrators. When we read the user list, we split it in 3: the admins, the writers and the readers. The writers are the users who are not in the read list and the write list. */ for (int i=0; iget(); if (admins.lookup(u) == -1 && readers.lookup(u)==-1){ writers.add (new SSTRING(u)); } } }else{ admin.setfrom (user); dia.last_noempty(); } dia.newf_str (MSG_U(F_ADMIN,"Administrators"),admin); dia.newf_str (MSG_U(F_COMMENT,"Description"),comment); dia.newf_chk (MSG_U(F_ENABLED,"Share is"),enabled,MSG_U(I_ENABLED,"enabled")); dia.newf_chk (MSG_U(F_WRITABLE,"Share is"),writable,MSG_U(I_WRITABLE,"writable")); // Add 10 spares for (int i=0; i<10; i++){ writers.add (new SSTRING); readers.add (new SSTRING); } dia.newf_title (MSG_U(T_WRITERS,"Writers"),1,"",MSG_R(T_WRITERS)); dia.newf_info ("",MSG_U(I_WRITERS,"These users and groups can write")); dia.newf_info ("",MSG_R(I_GROUPCHAR)); for (int i=0; i static void groupware_shares(const char *user) { SSTRINGS shares; const char *user; int nbshares; // Total number of groupware shares // not only those displayed glocal.user = user; /* #Specification: groupware / co-administrator logic This is a little tricky to explain. Basically, the module may be used in 3 mode: OPERMODE_NODE: Only root is allowed to configure special shares OPERMODE_COADMIN: Only root or co-administrators are allowed OPERMODE_ENDUSERS: Every body In the later case, we also filter the list of shares presented to the end users. Only the one where he is the first member (so the administrators) are shown. */ (MSG_U(T_GROUPSHARES,"Groupware shares") ,MSG_U(I_GROUPSHARES,"Here is the list of special shares\n" "allowing selected users to easily share documents") ,help_groupware); newf_head (MSG_U(H_GROUPSHARES,"Share\tComment\tAdministrator\tEnabled\tWritable")); sortable(); sortpolicy ("aaaaa"); sethdispo ("lllcc"); addwhat (MSG_U(I_NEWSHARE,"Use the [Add] button to add a new share")); glocal.nbshares = 0; glocal.shares.remove_all(); SSTRINGS tb; groupware_getshares(tb); master_registry.start_session(); for (int i=0; iget(); const char *desc = groupware_getreg ("comment",s); const char avail = groupware_getregnum ("available",s); const char writable = groupware_getregnum ("writable",s); SSTRINGS admins; groupware_getregu ("writelist",s,admins); if (glocal.user == NULL || admins.lookup(glocal.user)!=-1){ // Format the admin list and truncate as needed SSTRING tmp; for (int a=0; aget()); } if (tmp.getlen()>30) tmp.setfromf("%27.27s...",tmp.get()); new_menuitemf (s,"%s\t%s\t%c\t%c",desc,tmp.get() ,avail ? 'X' : ' ' ,writable ? 'X' : ' '); glocal.shares.add (new SSTRING(s)); } } master_registry.end_session(); groupware_edit (glocal.shares.getitem(no)->get(),glocal.user); int maxs = groupware_maxshareusers(); if (groupware_maxshares() <= glocal.nbshares){ xconf_error (MSG_U(E_TOOMANYSHARE ,"Sorry, too many groupware shares")); }else if (glocal.user == NULL || maxs > glocal.shares.getnb()){ groupware_edit (NULL,glocal.user); }else{ xconf_error (MSG_U(E_TOOMANYSHAREUSER ,"Sorry, too many shares\n" "you are only allowed to create %d"),maxs); } } static void groupware_shares() { if (perm_access (&p_shares,MSG_U(P_EDITSHARES,"edit groupware shares"))){ groupware_shares (NULL); } } /* Main menu for the module */ static void groupware_menu() { static const char *menuopt[]={ MSG_U(M_CONFIG,"Configure"),MSG_U(M_DEFAULT,"groupware settings"), "",MSG_U(M_SHARES,"special shares"), NULL }; (MSG_R(M_groupware),"",help_groupware,menuopt); if (no == 0){ groupware_settings(); }else if (no == 1){ groupware_shares(); } } static void groupware_htmlmsg (const char *msg) { html_printf ("\n"); html_printf ("%s\n",msg); html_printf ("

\n"); html_printf ("\n"); html_printf ("\n"); html_setdone(); } ("groupware",PACKAGE_REV); tb.add (new SSTRING(MSG_U(T_USAGE ,"linuxconf --modulemain groupware usage\n" "\n" " groupware --option ...\n"))); if (context == MENU_MISCSERV){ keymenu = MSG_U(M_groupware,"groupware/shares"); dia.new_menuitem ("groupware","",keymenu); } if (context == MENU_MISCSERV){ if (key == keymenu){ CONTEXT_LOCK l("groupware"); if (l.isok()){ groupware_menu(); } } } return 0; int ret = LNCF_NOT_APPLICABLE; if (strcmp(msg,"listspc")==0 && groupware_opermode() > OPERMODE_NONE){ html_printf ("

\n"); html_printf ("

%s
\n" ,MSG_U(I_GROUPWARE,"Define groupware shares")); html_printf ("

\n"); ret = 0; } return ret; int ret = LNCF_NOT_APPLICABLE; if (strcmp(key,"groupware")==0){ int uid = perm_getadminuid(); if (uid == -1){ html_needpasswd(); }else{ if (perm_checkpriv(&p_shares)){ // Ok, this is a co-admin, or root groupware_shares (); }else{ // end users if (groupware_opermode() != OPERMODE_ENDUSERS){ groupware_htmlmsg (MSG_U(I_NOSERVICE,"Sorry, the groupware service is disabled")); }else{ struct passwd *p = getpwuid(uid); if (p != NULL){ SSTRINGS users; groupware_allowedusers(users); int n = users.getnb(); bool ok = n==0; // If there is no user defined // everybody is allowed fprintf (stderr,"groupware n=%d\n",n); for (int i=0; iget(); fprintf (stderr,"groupware u=%s name=%s\n",u,p->pw_name); if (u[0] == '@'){ struct group *g = getgrnam(u+1); if (g != NULL && g->gr_gid == p->pw_gid){ ok = true; break; } }else if (strcmp(p->pw_name,u)==0){ ok = true; break; } } if (ok){ SSTRING user (p->pw_name); groupware_shares (user.get()); }else{ groupware_htmlmsg (MSG_U(I_NOTFORYOU ,"Sorry, the groupware service is not available to you
\n" "Please contact your boss or teacher\n")); } } } } } ret = 0; } return ret;
int ret = -1; if (argc == 1){ CONTEXT_LOCK l("groupware"); if (l.isok() && netconf_mainaccess()){ groupware_menu(); } }else{ printusage(); } return ret; static PUBLISH_VARIABLES_MSG groupware_var_list1[]={ {"group",P_MSG_R(F_GROUP)}, {"basedir",P_MSG_R(F_BASEDIR)}, {"mode",P_MSG_R(F_OPERMODE)}, {"maxshares",P_MSG_R(F_MAXSHARES)}, {"maxusershares",P_MSG_R(F_MAXSHAREUSERS)}, {"user1",P_MSG_R(F_USERS)}, { NULL, NULL } }; static REGISTER_VARIABLES groupware_registry1("groupware" ,groupware_var_list1,NULL,groupware_settings); static PUBLISH_VARIABLES_STR groupware_var_list2[]={ {"user2",tbuser+1}, {"user3",tbuser+2}, {"user4",tbuser+3}, {"user5",tbuser+5}, { NULL, NULL } }; static REGISTER_VARIABLES groupware_registry2("groupware" ,groupware_var_list2,NULL,groupware_settings);