+static struct {
+ const char *option;
+ int bit;
+}tbcap[]={
+ // The following capabilities are normally available
+ // to vservers administrator, but are place for
+ // completeness
+ {"CAP_CHOWN",CAP_CHOWN},
+ {"CAP_DAC_OVERRIDE",CAP_DAC_OVERRIDE},
+ {"CAP_DAC_READ_SEARCH",CAP_DAC_READ_SEARCH},
+ {"CAP_FOWNER",CAP_FOWNER},
+ {"CAP_FSETID",CAP_FSETID},
+ {"CAP_KILL",CAP_KILL},
+ {"CAP_SETGID",CAP_SETGID},
+ {"CAP_SETUID",CAP_SETUID},
+ {"CAP_SETPCAP",CAP_SETPCAP},
+ {"CAP_SYS_TTY_CONFIG",CAP_SYS_TTY_CONFIG},
+ {"CAP_LEASE",CAP_LEASE},
+ {"CAP_SYS_CHROOT",CAP_SYS_CHROOT},
+
+ // Those capabilities are not normally available
+ // to vservers because they are not needed and
+ // may represent a security risk
+ {"CAP_LINUX_IMMUTABLE",CAP_LINUX_IMMUTABLE},
+ {"CAP_NET_BIND_SERVICE",CAP_NET_BIND_SERVICE},
+ {"CAP_NET_BROADCAST",CAP_NET_BROADCAST},
+ {"CAP_NET_ADMIN", CAP_NET_ADMIN},
+ {"CAP_NET_RAW", CAP_NET_RAW},
+ {"CAP_IPC_LOCK", CAP_IPC_LOCK},
+ {"CAP_IPC_OWNER", CAP_IPC_OWNER},
+ {"CAP_SYS_MODULE",CAP_SYS_MODULE},
+ {"CAP_SYS_RAWIO", CAP_SYS_RAWIO},
+ {"CAP_SYS_PACCT", CAP_SYS_PACCT},
+ {"CAP_SYS_ADMIN", CAP_SYS_ADMIN},
+ {"CAP_SYS_BOOT", CAP_SYS_BOOT},
+ {"CAP_SYS_NICE", CAP_SYS_NICE},
+ {"CAP_SYS_RESOURCE",CAP_SYS_RESOURCE},
+ {"CAP_SYS_TIME", CAP_SYS_TIME},
+ {"CAP_MKNOD", CAP_MKNOD},
+#ifdef CAP_QUOTACTL
+ {"CAP_QUOTACTL", CAP_QUOTACTL},
+#endif
+ {NULL,0}
+};
+
+#define VSERVERCONF "/etc/vservers/"
+static unsigned get_remove_cap(char *name) {
+ FILE *fb;
+ unsigned remove_cap;
+
+ char *vserverconf;
+ int vserverconflen;
+
+ remove_cap = /* NOTE: keep in sync with chcontext.c */
+ (1<<CAP_LINUX_IMMUTABLE)|
+ (1<<CAP_NET_BROADCAST)|
+ (1<<CAP_NET_ADMIN)|
+ (1<<CAP_NET_RAW)|
+ (1<<CAP_IPC_LOCK)|
+ (1<<CAP_IPC_OWNER)|
+ (1<<CAP_SYS_MODULE)|
+ (1<<CAP_SYS_RAWIO)|
+ (1<<CAP_SYS_PACCT)|
+ (1<<CAP_SYS_ADMIN)|
+ (1<<CAP_SYS_BOOT)|
+ (1<<CAP_SYS_NICE)|
+ (1<<CAP_SYS_RESOURCE)|
+ (1<<CAP_SYS_TIME)|
+ (1<<CAP_MKNOD)|
+#ifdef CAP_QUOTACTL
+ (1<<CAP_QUOTACTL)|
+#endif
+#ifdef CAP_CONTEXT
+ (1<<CAP_CONTEXT)|
+#endif
+ 0
+ ;
+
+ /*
+ * find out which capabilities to put back in by reading the conf file
+ */
+
+ /* construct the pathname to the conf file */
+ vserverconflen = strlen(VSERVERCONF) + strlen(name) + strlen(".conf") + NULLBYTE_SIZE;
+ vserverconf = (char *)malloc(vserverconflen);
+ sprintf(vserverconf, "%s%s.conf", VSERVERCONF, name);
+
+ fprintf(stderr,"opening file %s\n",vserverconf);
+ /* open the conf file for reading */
+ fb = fopen(vserverconf,"r");
+ if (fb != NULL) {
+ int index;
+ unsigned cap;
+ ssize_t bufsize;
+ size_t len = 0;
+ char *buffer = NULL;
+
+ /* the conf file file exist */
+ while((bufsize = getline(&buffer,&len,fb))>0) {
+ index = 0;
+
+ /* walk past leading spaces */
+ while(isspace((int)buffer[index]) && (index < bufsize)) index++;
+
+ /* ignore if it's a comment */
+ if ((buffer[index] == '#') || (index >= bufsize)) continue;
+
+ /* check if it is the S_CAPS */
+ if (strstr(buffer,"S_CAPS")!=NULL) {
+ int j;
+ cap = 0;
+
+ fprintf(stderr,"Found S_CAPS\n");
+ for (j=0; tbcap[j].option != NULL; j++){
+ if (strstr(buffer,tbcap[j].option)!=NULL){
+ fprintf(stderr,"%s\n",tbcap[j].option);
+ cap |= (1<<tbcap[j].bit);
+ }
+ }
+ remove_cap &= ~cap;
+ break;
+ }
+ }
+ /* close the conf file */
+ fclose(fb);
+ } else {
+ fprintf(stderr,"failed to open %s\n",vserverconf);
+ }
+ return remove_cap;
+}
+
+static int sandbox_processes(uid_t uid, unsigned remove_cap)