chiark / gitweb /
stuff from chiark:/usr/local/src/misc/ (as found)
authorianmdlvl <ianmdlvl>
Wed, 2 Jul 2003 18:20:29 +0000 (18:20 +0000)
committerianmdlvl <ianmdlvl>
Wed, 2 Jul 2003 18:20:29 +0000 (18:20 +0000)
19 files changed:
cprogs/myopt.c [new file with mode: 0644]
cprogs/myopt.c~ [new file with mode: 0644]
cprogs/myopt.h [new file with mode: 0644]
cprogs/myopt.h~ [new file with mode: 0644]
cprogs/really [new file with mode: 0755]
cprogs/really-test [new file with mode: 0755]
cprogs/really.c [new file with mode: 0644]
cprogs/really.c~ [new file with mode: 0644]
cprogs/really.testcases [new file with mode: 0755]
cprogs/smtpallow.c [new file with mode: 0644]
cprogs/smtpallow.c~ [new file with mode: 0644]
cprogs/smtpallow.o [new file with mode: 0644]
cprogs/smtpallow.so [new file with mode: 0755]
cprogs/usernice.c [new file with mode: 0644]
cprogs/usr-local-src-misc-Makefile [new file with mode: 0644]
cprogs/usr-local-src-misc-Makefile~ [new file with mode: 0644]
debian/changelog
scripts/cvsweb-list [new file with mode: 0755]
scripts/cvsweb-list~ [new file with mode: 0755]

diff --git a/cprogs/myopt.c b/cprogs/myopt.c
new file mode 100644 (file)
index 0000000..ab89df8
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * myopt.c - my very own option parsing
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "myopt.h"
+
+void badusage(const char *fmt, ...) {
+  va_list al;
+  
+  va_start(al,fmt);
+  vfprintf(stderr,fmt,al);
+  va_end(al);
+  fputc('\n',stderr);
+  usagemessage();
+  exit(-1);
+}
+
+void myopt(const char *const **argvp, const struct cmdinfo *cmdinfos) {
+  const struct cmdinfo *cip;
+  const char *p, *value;
+  int l;
+
+  ++(*argvp);
+  while ((p= **argvp) && *p == '-') {
+    ++(*argvp);
+    if (!strcmp(p,"--")) break;
+    if (*++p == '-') {
+      ++p; value=0;
+      for (cip= cmdinfos;
+           cip->olong || cip->oshort;
+           cip++) {
+        if (!cip->olong) continue;
+        if (!strcmp(p,cip->olong)) break;
+        l= strlen(cip->olong);
+        if (!strncmp(p,cip->olong,l) &&
+            (p[l]== ((cip->takesvalue==2) ? '-' : '='))) { value=p+l+1; break; }
+      }
+      if (!cip->olong) badusage("unknown option --%s",p);
+      if (cip->takesvalue) {
+        if (!value) {
+          value= *(*argvp)++;
+          if (!value) badusage("--%s option takes a value",cip->olong);
+        }
+        if (cip->call) cip->call(cip,value);
+        else *cip->sassignto= value;
+      } else {
+        if (value) badusage("--%s option does not take a value",cip->olong);
+        if (cip->call) cip->call(cip,0);
+        else *cip->iassignto= cip->arg;
+      }
+    } else {
+      while (*p) {
+        for (cip= cmdinfos; (cip->olong || cip->oshort) && *p != cip->oshort; cip++);
+        if (!cip->oshort) badusage("unknown option -%c",*p);
+        p++;
+        if (cip->takesvalue) {
+          if (!*p) {
+            value= *(*argvp)++;
+            if (!value) badusage("-%c option takes a value",cip->oshort);
+          } else {
+            value= p; p="";
+            if (*value == '=') value++;
+          }
+          if (cip->call) cip->call(cip,value);
+          else *cip->sassignto= value;
+        } else {
+          if (*p == '=') badusage("-%c option does not take a value",cip->oshort);
+          if (cip->call) cip->call(cip,0);
+          else *cip->iassignto= cip->arg;
+        }
+      }
+    }
+  }
+}
diff --git a/cprogs/myopt.c~ b/cprogs/myopt.c~
new file mode 100644 (file)
index 0000000..b3c2167
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * myopt.c - my very own option parsing
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+
+#include "config.h"
+#include "myopt.h"
+#include "dpkg.h"
+
+void myopt(const char *const **argvp, const struct cmdinfo *cmdinfos) {
+  const struct cmdinfo *cip;
+  const char *p, *value;
+  int l;
+
+  ++(*argvp);
+  while ((p= **argvp) && *p == '-') {
+    ++(*argvp);
+    if (!strcmp(p,"--")) break;
+    if (*++p == '-') {
+      ++p; value=0;
+      for (cip= cmdinfos;
+           cip->olong || cip->oshort;
+           cip++) {
+        if (!cip->olong) continue;
+        if (!strcmp(p,cip->olong)) break;
+        l= strlen(cip->olong);
+        if (!strncmp(p,cip->olong,l) &&
+            (p[l]== ((cip->takesvalue==2) ? '-' : '='))) { value=p+l+1; break; }
+      }
+      if (!cip->olong) badusage("unknown option --%s",p);
+      if (cip->takesvalue) {
+        if (!value) {
+          value= *(*argvp)++;
+          if (!value) badusage("--%s option takes a value",cip->olong);
+        }
+        if (cip->call) cip->call(cip,value);
+        else *cip->sassignto= value;
+      } else {
+        if (value) badusage("--%s option does not take a value",cip->olong);
+        if (cip->call) cip->call(cip,0);
+        else *cip->iassignto= cip->arg;
+      }
+    } else {
+      while (*p) {
+        for (cip= cmdinfos; (cip->olong || cip->oshort) && *p != cip->oshort; cip++);
+        if (!cip->oshort) badusage("unknown option -%c",*p);
+        p++;
+        if (cip->takesvalue) {
+          if (!*p) {
+            value= *(*argvp)++;
+            if (!value) badusage("-%c option takes a value",cip->oshort);
+          } else {
+            value= p; p="";
+            if (*value == '=') value++;
+          }
+          if (cip->call) cip->call(cip,value);
+          else *cip->sassignto= value;
+        } else {
+          if (*p == '=') badusage("-%c option does not take a value",cip->oshort);
+          if (cip->call) cip->call(cip,0);
+          else *cip->iassignto= cip->arg;
+        }
+      }
+    }
+  }
+}
diff --git a/cprogs/myopt.h b/cprogs/myopt.h
new file mode 100644 (file)
index 0000000..6e1200c
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * myopt.h - declarations for my very own option parsing
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MYOPT_H
+#define MYOPT_H
+
+extern void usagemessage(void); /* supply this */
+
+typedef void (*voidfnp)(void);
+
+struct cmdinfo {
+  const char *olong;
+  char oshort;
+  int takesvalue; /* 0 = normal   1 = standard value   2 = option string cont */
+  int *iassignto;
+  const char **sassignto;
+  void (*call)(const struct cmdinfo*, const char *value);
+  int arg;
+  void *parg;
+  voidfnp farg;
+};
+
+void myopt(const char *const **argvp, const struct cmdinfo *cmdinfos);
+void badusage(const char *fmt, ...);
+
+#endif /* MYOPT_H */
diff --git a/cprogs/myopt.h~ b/cprogs/myopt.h~
new file mode 100644 (file)
index 0000000..0b28d09
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * myopt.h - declarations for my very own option parsing
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MYOPT_H
+#define MYOPT_H
+
+typedef void (*voidfnp)(void);
+
+struct cmdinfo {
+  const char *olong;
+  char oshort;
+  int takesvalue; /* 0 = normal   1 = standard value   2 = option string cont */
+  int *iassignto;
+  const char **sassignto;
+  void (*call)(const struct cmdinfo*, const char *value);
+  int arg;
+  void *parg;
+  voidfnp farg;
+};
+
+void myopt(const char *const **argvp, const struct cmdinfo *cmdinfos);
+
+#endif /* MYOPT_H */
diff --git a/cprogs/really b/cprogs/really
new file mode 100755 (executable)
index 0000000..083f0ef
Binary files /dev/null and b/cprogs/really differ
diff --git a/cprogs/really-test b/cprogs/really-test
new file mode 100755 (executable)
index 0000000..d8d9b3e
Binary files /dev/null and b/cprogs/really-test differ
diff --git a/cprogs/really.c b/cprogs/really.c
new file mode 100644 (file)
index 0000000..b240ea4
--- /dev/null
@@ -0,0 +1,210 @@
+/**/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "myopt.h"
+
+void usagemessage(void) {
+  if (fputs("usage: really [<user-option>] [<group-option> ...] [--]"
+            " [<command> [<argument/option> ...]]\n"
+            "user-options:\n"
+            " if no options given, set the uid to 0;\n"
+            " -u|--user <username>     also sets their default group list\n"
+            " -i|--useronly <username> } set the uid\n"
+            " -I|--uidonly <uid>       }  but inherits the group list\n"
+            "group-options:\n"
+            " -z|--groupsclear         only groups specified are to be used\n"
+            " -g|--group <groupname>   } add this to\n"
+            " -G|--gid <gid>           }  the group list\n",
+            stderr) == EOF) { perror("write usage"); exit(-1); }
+}
+
+static const char *opt_user, *opt_useronly;
+static int opt_groupsclear= 0, opt_ngids= 0, opt_uidonly= -1;
+static int opt_gids[512];
+
+static void af_group(const struct cmdinfo *cip, const char *value) {
+  struct group *gr;
+
+  if (opt_ngids >= sizeof(opt_gids)/sizeof(opt_gids[0]))
+    badusage("too many groups specified");
+  gr= getgrnam(value);
+  if (!gr) { fprintf(stderr,"unknown group `%s'\n",value); exit(-1); }
+  opt_gids[opt_ngids++]= gr->gr_gid;
+}
+
+static void af_gid(const struct cmdinfo *cip, const char *value) {
+  char *ep;
+  unsigned long ul;
+
+  if (opt_ngids >= sizeof(opt_gids)/sizeof(opt_gids[0]))
+    badusage("too many gids specified");
+  ul= strtoul(value,&ep,0);
+  if ((*ep) || (uid_t)ul != ul || ul>INT_MAX) badusage("bad gid `%s'",value);
+  opt_gids[opt_ngids++]= ul;
+}
+
+static void af_help(const struct cmdinfo *cip, const char *value) {
+  usagemessage(); exit(0);
+}
+
+static const struct cmdinfo cmdinfos[]= {
+  { "user",         'u',  1,  0, &opt_user,          0,           },
+  { "useronly",     'i',  1,  0, &opt_useronly,      0            },
+  { "uidonly",      'I',  1,  &opt_uidonly, 0,       0            },
+  { "groupsclear",  'z',  0,  &opt_groupsclear, 0,   0,        1  },
+  { "group",        'g',  1,  0, 0,                  af_group     },
+  { "gid",          'G',  1,  0, 0,                  af_gid       },
+  { "help",         'h',  0,  0, 0,                  af_help      },
+  {  0,              0                                            }
+};
+
+#ifdef REALLY_CHECK_FILE
+static void checkroot(void) {
+  int r;
+  r= access(REALLY_CHECK_FILE,W_OK);
+  if (r) { perror("sorry"); exit(-1); }
+}
+#endif
+#ifdef REALLY_CHECK_GID
+static void checkroot(void) {
+  gid_t groups[512];
+  int r;
+
+  r= getgid(); if (r==REALLY_CHECK_GID) return;
+  if (r<0) { perror("getgid check"); exit(-1); }
+  r= getgroups(sizeof(groups)/sizeof(groups[0]),groups);
+  if (r<0) { perror("getgroups check"); exit(-1); }
+  for (i=0; i<r; i++)
+    if (groups[i] == REALLY_CHECK_GID) return;
+  fputs("sorry\n",stderr); exit(-1);
+}
+#endif
+#ifdef REALLY_CHECK_NONE
+static void checkroot(void) {
+}
+#endif
+
+int main(int argc, const char *const *argv) {
+  struct passwd *pw= 0;
+  gid_t groups[512];
+  int i, j, ngroups, ngroups_in, maingid, orgmaingid, mainuid, orgmainuid, r;
+  const char *cp;
+  
+  checkroot();
+  myopt(&argv,cmdinfos);
+
+  if (opt_groupsclear && !opt_ngids)
+    badusage("-z|--groupsclear must be accompanied by some groups");
+  if (opt_user && (opt_useronly || opt_uidonly!=-1))
+    badusage("-u|--user may not be used with -i|--useronly or -I|--uidonly");
+  if (opt_user && opt_groupsclear)
+    badusage("-u|--user may not be used with -z|--groupsclear");
+  if (opt_uidonly != -1 && (uid_t)opt_uidonly != opt_uidonly)
+    badusage("-I|--uidonly value %d is out of range for a uid",opt_uidonly);
+
+  if (!opt_user && !opt_useronly && opt_uidonly==-1 && !opt_ngids) {
+    opt_uidonly= 0;
+  }
+  if (opt_user || opt_useronly) {
+    cp= opt_user ? opt_user : opt_useronly;
+    pw= getpwnam(cp);
+    if (!pw) { fprintf(stderr,"unknown user `%s'\n",cp); exit(-1); }
+    opt_uidonly= pw->pw_uid;
+  }
+  orgmaingid= getgid();
+  orgmainuid= getuid();
+  if (orgmaingid<0) { perror("getgid failed"); exit(-1); }
+  if (opt_user) {
+    r= initgroups(opt_user,pw->pw_gid);
+    if (r) { perror("initgroups failed"); exit(-1); }
+    maingid= pw->pw_gid;
+  } else {
+    maingid= -1;
+  }
+  if (opt_groupsclear) {
+    ngroups= 0;
+    if (opt_ngids > sizeof(groups)/sizeof(groups[0])) {
+      fputs("too many groups to set\n",stderr);
+      exit(-1);
+    }
+  } else {
+    ngroups= getgroups(0,0);
+    if (ngroups<0) { perror("getgroups(0,0) failed"); exit(-1); }
+    if (ngroups+opt_ngids > sizeof(groups)/sizeof(groups[0])) {
+      fputs("too many groups already set for total to fit\n",stderr);
+      exit(-1);
+    }
+    ngroups= getgroups(ngroups,groups);
+    if (ngroups<0) { perror("getgroups failed"); exit(-1); }
+  }
+  if (opt_ngids) {
+    maingid= opt_gids[0];
+  }
+  if (opt_ngids || opt_groupsclear) {
+    ngroups_in= ngroups; ngroups= 0;
+    for (i=0; i<ngroups_in; i++) {
+      for (j=0; j<ngroups && groups[j] != groups[i]; j++);
+      if (j<ngroups) continue;
+      groups[ngroups++]= groups[i];
+    }
+    for (i=0; i<opt_ngids; i++) {
+      for (j=0; j<ngroups && groups[j] != opt_gids[i]; j++);
+      if (j<ngroups) continue;
+      groups[ngroups++]= opt_gids[i];
+    }
+    r= setgroups(ngroups,groups);
+    if (r) { perror("setgroups failed"); exit(-1); }
+  }
+  if (maingid != -1) {
+    r= setgid(maingid); if (r) { perror("setgid failed"); exit(-1); }
+    r= setgid(maingid); if (r) { perror("2nd setgid failed"); exit(-1); }
+  }
+  if (opt_uidonly != -1) {
+    mainuid= opt_uidonly;
+  } else {
+    mainuid= orgmainuid;
+  }
+  r= setuid(mainuid); if (r) { perror("setuid failed"); exit(-1); }
+  r= setuid(mainuid); if (r) { perror("2nd setuid failed"); exit(-1); }
+  if (mainuid != 0) {
+    r= seteuid(0); if (r>=0) { fputs("could seteuid 0",stderr); exit(-1); }
+    if (errno != EPERM) {
+      perror("unexpected failure mode for seteuid 0"); exit(-1);
+    }
+  }
+  r= getuid(); if (r<0) { perror("getuid failed"); exit(-1); }
+  if (r != mainuid) { fputs("getuid mismatch",stderr); exit(-1); }
+  r= geteuid(); if (r<0) { perror("geteuid failed"); exit(-1); }
+  if (r != mainuid) { fputs("geteuid mismatch",stderr); exit(-1); }
+  if (maingid != -1) {
+    for (i=0; i<ngroups && maingid != groups[i]; i++);
+    if (i>=ngroups && maingid != orgmaingid) {
+      r= setgid(orgmaingid);
+      if (r>=0) { fputs("could setgid back",stderr); exit(-1); }
+      if (errno != EPERM) {
+        perror("unexpected failure mode for setgid back"); exit(-1);
+      }
+    }
+    r= getgid(); if (r<0) { perror("getgid failed"); exit(-1); }
+    if (r != maingid) { fputs("getgid mismatch",stderr); exit(-1); }
+    r= getegid(); if (r<0) { perror("getegid failed"); exit(-1); }
+    if (r != maingid) { fputs("getegid mismatch",stderr); exit(-1); }
+  }
+  if (!*argv) {
+    cp= getenv("SHELL");
+    if (!cp) cp= "sh";
+    execlp(cp,cp,"-i",(const char*)0);
+  } else {
+    execvp(argv[0],(char**)argv);
+  }
+  perror("exec failed");
+  exit(-1);
+}
diff --git a/cprogs/really.c~ b/cprogs/really.c~
new file mode 100644 (file)
index 0000000..19e642e
--- /dev/null
@@ -0,0 +1,209 @@
+/**/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+
+#include "myopt.h"
+
+void usagemessage(void) {
+  if (fputs("usage: really [<user-option>] [<group-option> ...] [--]"
+            " [<command> [<argument/option> ...]]\n"
+            "user-options:\n"
+            " if no options given, set the uid to 0;\n"
+            " -u|--user <username>     also sets their default group list\n"
+            " -i|--useronly <username> } set the uid\n"
+            " -I|--uidonly <uid>       }  but inherits the group list\n"
+            "group-options:\n"
+            " -z|--groupsclear         only groups specified are to be used\n"
+            " -g|--group <groupname>   } add this to\n"
+            " -G|--gid <gid>           }  the group list\n",
+            stderr) == EOF) { perror("write usage"); exit(-1); }
+}
+
+static const char *opt_user, *opt_useronly;
+static int opt_groupsclear= 0, opt_ngids= 0, opt_uidonly= -1;
+static int opt_gids[512];
+
+static void af_group(const struct cmdinfo *cip, const char *value) {
+  struct group *gr;
+
+  if (opt_ngids >= sizeof(opt_gids)/sizeof(opt_gids[0]))
+    badusage("too many groups specified");
+  gr= getgrnam(value);
+  if (!gr) { fprintf(stderr,"unknown group `%s'\n",value); exit(-1); }
+  opt_gids[opt_ngids++]= gr->gr_gid;
+}
+
+static void af_gid(const struct cmdinfo *cip, const char *value) {
+  char *ep;
+  unsigned long ul;
+
+  if (opt_ngids >= sizeof(opt_gids)/sizeof(opt_gids[0]))
+    badusage("too many gids specified");
+  ul= strtoul(value,&ep,0);
+  if ((*ep) || (uid_t)ul != ul || ul>INT_MAX) badusage("bad gid `%s'",value);
+  opt_gids[opt_ngids++]= ul;
+}
+
+static void af_help(const struct cmdinfo *cip, const char *value) {
+  usagemessage(); exit(0);
+}
+
+static const struct cmdinfo cmdinfos[]= {
+  { "user",         'u',  1,  0, &opt_user,          0,           },
+  { "useronly",     'i',  1,  0, &opt_useronly,      0            },
+  { "uidonly",      'I',  1,  &opt_uidonly, 0,       0            },
+  { "groupsclear",  'z',  0,  &opt_groupsclear, 0,   0,        1  },
+  { "group",        'g',  1,  0, 0,                  af_group     },
+  { "gid",          'G',  1,  0, 0,                  af_gid       },
+  { "help",         'h',  0,  0, 0,                  af_help      },
+  {  0,              0                                            }
+};
+
+#ifdef REALLY_CHECK_FILE
+void checkroot(void) {
+  int r;
+  r= access(REALLY_CHECK_FILE,W_OK);
+  if (r) { perror("sorry"); exit(-1); }
+}
+#endif
+#ifdef REALLY_CHECK_GID
+void checkroot(void) {
+  gid_t groups[512];
+  int r;
+
+  r= getgid(); if (r==REALLY_CHECK_GID) return;
+  if (r<0) { perror("getgid check"); exit(-1); }
+  r= getgroups(sizeof(groups)/sizeof(groups[0]),groups);
+  if (r<0) { perror("getgroups check"); exit(-1); }
+  for (i=0; i<r; i++)
+    if (groups[i] == REALLY_CHECK_GID) return;
+  fputs("sorry\n",stderr); exit(-1);
+}
+#endif
+#ifdef REALLY_CHECK_NONE
+void checkroot(void) {
+}
+#endif
+
+int main(int argc, const char *const *argv) {
+  struct passwd *pw= 0;
+  gid_t groups[512];
+  int i, j, ngroups, ngroups_in, maingid, orgmaingid, mainuid, orgmainuid, r;
+  const char *cp;
+  
+  checkroot();
+  myopt(&argv,cmdinfos);
+
+  if (opt_groupsclear && !opt_ngids)
+    badusage("-z|--groupsclear must be accompanied by some groups");
+  if (opt_user && (opt_useronly || opt_uidonly!=-1))
+    badusage("-u|--user may not be used with -i|--useronly or -I|--uidonly");
+  if (opt_user && opt_groupsclear)
+    badusage("-u|--user may not be used with -z|--groupsclear");
+  if (opt_uidonly != -1 && (uid_t)opt_uidonly != opt_uidonly)
+    badusage("-I|--uidonly value %d is out of range for a uid",opt_uidonly);
+
+  if (!opt_user && !opt_useronly && opt_uidonly==-1 && !opt_ngids) {
+    opt_uidonly= 0;
+  }
+  if (opt_user || opt_useronly) {
+    cp= opt_user ? opt_user : opt_useronly;
+    pw= getpwnam(cp);
+    if (!pw) { fprintf(stderr,"unknown user `%s'\n",cp); exit(-1); }
+    opt_uidonly= pw->pw_uid;
+  }
+  orgmaingid= getgid();
+  orgmainuid= getuid();
+  if (orgmaingid<0) { perror("getgid failed"); exit(-1); }
+  if (opt_user) {
+    r= initgroups(opt_user,pw->pw_gid);
+    if (r) { perror("initgroups failed"); exit(-1); }
+    maingid= pw->pw_gid;
+  } else {
+    maingid= -1;
+  }
+  if (opt_groupsclear) {
+    ngroups= 0;
+    if (opt_ngids > sizeof(groups)/sizeof(groups[0])) {
+      fputs("too many groups to set\n",stderr);
+      exit(-1);
+    }
+  } else {
+    ngroups= getgroups(0,0);
+    if (ngroups<0) { perror("getgroups(0,0) failed"); exit(-1); }
+    if (ngroups+opt_ngids > sizeof(groups)/sizeof(groups[0])) {
+      fputs("too many groups already set for total to fit\n",stderr);
+      exit(-1);
+    }
+    ngroups= getgroups(ngroups,groups);
+    if (ngroups<0) { perror("getgroups failed"); exit(-1); }
+  }
+  if (opt_ngids) {
+    maingid= opt_gids[0];
+  }
+  if (opt_ngids || opt_groupsclear) {
+    ngroups_in= ngroups; ngroups= 0;
+    for (i=0; i<ngroups_in; i++) {
+      for (j=0; j<ngroups && groups[j] != groups[i]; j++);
+      if (j<ngroups) continue;
+      groups[ngroups++]= groups[i];
+    }
+    for (i=0; i<opt_ngids; i++) {
+      for (j=0; j<ngroups && groups[j] != opt_gids[i]; j++);
+      if (j<ngroups) continue;
+      groups[ngroups++]= opt_gids[i];
+    }
+    r= setgroups(ngroups,groups);
+    if (r) { perror("setgroups failed"); exit(-1); }
+  }
+  if (maingid != -1) {
+    r= setgid(maingid); if (r) { perror("setgid failed"); exit(-1); }
+    r= setgid(maingid); if (r) { perror("2nd setgid failed"); exit(-1); }
+  }
+  if (opt_uidonly != -1) {
+    mainuid= opt_uidonly;
+  } else {
+    mainuid= orgmainuid;
+  }
+  r= setuid(mainuid); if (r) { perror("setuid failed"); exit(-1); }
+  r= setuid(mainuid); if (r) { perror("2nd setuid failed"); exit(-1); }
+  if (mainuid != 0) {
+    r= seteuid(0); if (r>=0) { fputs("could seteuid 0",stderr); exit(-1); }
+    if (errno != EPERM) {
+      perror("unexpected failure mode for seteuid 0"); exit(-1);
+    }
+  }
+  r= getuid(); if (r<0) { perror("getuid failed"); exit(-1); }
+  if (r != mainuid) { fputs("getuid mismatch",stderr); exit(-1); }
+  r= geteuid(); if (r<0) { perror("geteuid failed"); exit(-1); }
+  if (r != mainuid) { fputs("geteuid mismatch",stderr); exit(-1); }
+  if (maingid != -1) {
+    for (i=0; i<ngroups && maingid != groups[i]; i++);
+    if (i>=ngroups && maingid != orgmaingid) {
+      r= setgid(orgmaingid);
+      if (r>=0) { fputs("could setgid back",stderr); exit(-1); }
+      if (errno != EPERM) {
+        perror("unexpected failure mode for setgid back"); exit(-1);
+      }
+    }
+    r= getgid(); if (r<0) { perror("getgid failed"); exit(-1); }
+    if (r != maingid) { fputs("getgid mismatch",stderr); exit(-1); }
+    r= getegid(); if (r<0) { perror("getegid failed"); exit(-1); }
+    if (r != maingid) { fputs("getegid mismatch",stderr); exit(-1); }
+  }
+  if (!*argv) {
+    cp= getenv("SHELL");
+    if (!cp) cp= "sh";
+    execlp(cp,cp,"-i",(const char*)0);
+  } else {
+    execvp(argv[0],(char**)argv);
+  }
+  perror("exec failed");
+  exit(-1);
+}
diff --git a/cprogs/really.testcases b/cprogs/really.testcases
new file mode 100755 (executable)
index 0000000..153e47c
--- /dev/null
@@ -0,0 +1,164 @@
+#!/usr/bin/perl
+
+$testuser=   'testac';
+$testgroup=  'testac';
+$testuid=    1000;
+$testgid=    1000;
+@testxgids=  qw(1000);
+$numgid=     50008;
+$othergroup= 'daemon';
+$othergid=   1;
+
+sub parseid ($) {
+    my ($id) = @_;
+    my $orgid= $id;
+    my $out= '';
+    my $part;
+    chomp($id);
+    $id =~ s/^uid=// or return $id =~ m/\n/ ? "ERROR: $`" : "ERROR: $id";
+    $id =~ s/^(\d+)// or return $orgid;
+    $out= $1;
+    $id =~ s/^\([^\)]+\)//; $id =~ s/^\s+// or return $orgid;
+    $id =~ s/^gid=(\d+)// or return $orgid;
+    $out.= " $1";
+    $id =~ s/^\([^\)]+\)//; $id =~ s/^\s+// or return $orgid;
+    $id =~ s/^groups=// or return $orgid;
+    for $part (split(/,/,$id)) {
+        $part =~ s/^(\d+)// or return $orgid;
+        $out.= " $1";
+        $part =~ s/^\([^\)]+\)//; $part eq '' or return $orgid;
+    }
+    return $out;
+}
+
+$org= `id`;
+$org =~ m/^uid=\d+\(([^\)]+)\) gid=\d+\(([^\)]+)\) / or die "$org ?";
+$orguser= $1; $orggroup= $2;
+$org= parseid($org);
+$org =~ m/^\d+ \d+ / or die $org;
+($orguid,$orggid,@orgxgids)= split(/ /,$org);
+
+$tests= <<END;
+-u $testuser
+$testuid $testgid @testxgids
+
+-u $testuser -z
+ERROR: -z|--groupsclear must be accompanied by some groups
+
+-u $testuser -g $othergroup
+$testuid $othergid @testxgids $othergid
+
+-u $testuser -z -g $othergroup
+ERROR: -u|--user may not be used with -z|--groupsclear
+
+-u $testuser -G $numgid -g $othergroup
+$testuid $numgid @testxgids $numgid $othergid
+
+-u $testuser -z -G $numgid -g $othergroup
+ERROR: -u|--user may not be used with -z|--groupsclear
+
+-u $testuser -g $testgroup -G $testgid
+$testuid $testgid @testxgids
+
+-u $testuser -z -g $testgroup -G $testgid
+ERROR: -u|--user may not be used with -z|--groupsclear
+
+-u $testuser -g $othergroup -g $testgroup -G $testgid
+$testuid $othergid @testxgids $othergid
+
+-u $testuser -z -g $othergroup -g $testgroup -G $testgid
+ERROR: -u|--user may not be used with -z|--groupsclear
+
+-u $testuser -G $numgid -g $othergroup -g $testgroup -G $testgid
+$testuid $numgid @testxgids $numgid $othergid
+
+-u $testuser -z -G $numgid -g $othergroup -g $testgroup -G $testgid
+ERROR: -u|--user may not be used with -z|--groupsclear
+
+
+0 $orggid @orgxgids
+
+-i $testuser
+$testuid $orggid @orgxgids
+
+-i $testuser -z
+ERROR: -z|--groupsclear must be accompanied by some groups
+
+-i $testuser -g $othergroup
+$testuid $othergid @orgxgids $othergid
+
+-i $testuser -z -g $othergroup
+$testuid $othergid $othergid
+
+-i $testuser -G $numgid -g $othergroup
+$testuid $numgid @orgxgids $numgid $othergid
+
+-i $testuser -z -G $numgid -g $othergroup
+$testuid $numgid $numgid $othergid
+
+-i $testuser -g $orggroup -G $orggid
+$testuid $orggid @orgxgids
+
+-i $testuser -z -g $orggroup -G $orggid
+$testuid $orggid $orggid
+
+-i $testuser -g $othergroup -g $orggroup -G $orggid
+$testuid $othergid @orgxgids $othergid
+
+-i $testuser -z -g $othergroup -g $orggroup -G $orggid
+$testuid $othergid $othergid $orggid
+
+-i $testuser -G $numgid -g $othergroup -g $orggroup -G $orggid
+$testuid $numgid @orgxgids $numgid $othergid
+
+-i $testuser -z -G $numgid -g $othergroup -g $orggroup -G $orggid
+$testuid $numgid $numgid $othergid $orggid
+
+
+0 $orggid @orgxgids
+
+-z
+ERROR: -z|--groupsclear must be accompanied by some groups
+
+-g $othergroup
+$orguid $othergid @orgxgids $othergid
+
+-z -g $othergroup
+$orguid $othergid $othergid
+
+-G $numgid -g $othergroup
+$orguid $numgid @orgxgids $numgid $othergid
+
+-z -G $numgid -g $othergroup
+$orguid $numgid $numgid $othergid
+
+-g $orggroup -G $orggid
+$orguid $orggid @orgxgids
+
+-z -g $orggroup -G $orggid
+$orguid $orggid $orggid
+
+-g $othergroup -g $orggroup -G $orggid
+$orguid $othergid @orgxgids $othergid
+
+-z -g $othergroup -g $orggroup -G $orggid
+$orguid $othergid $othergid $orggid
+
+-G $numgid -g $othergroup -g $orggroup -G $orggid
+$orguid $numgid @orgxgids $numgid $othergid
+
+-z -G $numgid -g $othergroup -g $orggroup -G $orggid
+$orguid $numgid $numgid $othergid $orggid
+
+
+ERROR: sorry: Permission denied
+./really-test -u $testuser -g staff
+END
+
+@tests= split(/\n/,$tests);
+for ($i=0; $i<$#tests; $i+=3) {
+    $out= `$tests[$i+2] ./really-test $tests[$i] id 2>&1`;
+    $newout= parseid($out);
+    print("OK $tests[$i] ($tests[$i+2])\n"), next if $newout eq $tests[$i+1];
+    die "$newout != $tests[$i+1] ($tests[$i]) $i";
+}
diff --git a/cprogs/smtpallow.c b/cprogs/smtpallow.c
new file mode 100644 (file)
index 0000000..d8c8532
--- /dev/null
@@ -0,0 +1,44 @@
+/**/
+
+#include <syscall.h>
+#include <sys/socketcall.h>
+#include <netinet/in.h>
+#include <string.h>
+
+_syscall2(long,socketcall,int,call,unsigned long *,args);
+
+int real_connect(int sockfd, const struct sockaddr *saddr, int addrlen)
+{
+       unsigned long args[3];
+
+       args[0] = sockfd;
+       args[1] = (unsigned long)saddr;
+       args[2] = addrlen;
+       return socketcall(SYS_CONNECT, args);
+}
+
+int connect(int fd, const struct sockaddr *them_any, int addrlen) {
+  struct sockaddr_in *them= (struct sockaddr_in*)them_any;
+  int r,l,i;
+  struct sockaddr_in us;
+  
+  if (addrlen == sizeof(us) &&
+      them->sin_family == AF_INET &&
+      them->sin_port == htons(25)) {
+    memset(&us,0,sizeof(us));
+    us.sin_port= 0;
+    us.sin_family= AF_INET;
+    us.sin_addr.s_addr= INADDR_ANY;
+    r= getsockname(fd,(struct sockaddr*)&us,&l);
+    if (r<0 && errno != EINVAL) return r;
+    if (!ntohs(us.sin_port)) {
+      for (i=1023; i>0; i--) {
+        us.sin_port= htons(i);
+        if (!bind(fd,(struct sockaddr*)&us,sizeof(us))) break;
+        if (errno != EADDRINUSE) return -1;
+      }
+      if (!i) return -1;
+    } else if (r<0) return r;
+  }
+  return real_connect(fd,them_any,addrlen);
+}
diff --git a/cprogs/smtpallow.c~ b/cprogs/smtpallow.c~
new file mode 100644 (file)
index 0000000..83d0fc4
--- /dev/null
@@ -0,0 +1,35 @@
+/**/
+
+#include <netinet/in.h>
+
+_syscall2(long,socketcall,int,call,unsigned long *,args);
+int real_connect(int sockfd, const struct sockaddr *saddr, int addrlen)
+{
+       unsigned long args[3];
+
+       args[0] = sockfd;
+       args[1] = (unsigned long)saddr;
+       args[2] = addrlen;
+       return socketcall(SYS_CONNECT, args);
+}
+
+int connect(int fd, struct sockaddr_in *them, int *addrlen) {
+  int r,l;
+  struct sockaddr_in us;
+  pid_t c;
+  
+  if (*addrlen == sizeof(us) &&
+      them->sin_family == AF_INET &&
+      them->sin_port == htons(13)) {
+    r= getsockname(fd,&us,&l); if (r<0) return r;
+    if (!ntohs(us.port)) {
+      for (i=1023; i>0; i++) {
+        us.port= htons(i);
+        if (!bind(fd,&us,sizeof(us))) break;
+        if (errno != EADDRINUSE) return -1;
+      }
+      if (!i) return -1;
+    }
+  }
+  return real_connect(fd,them,addrlen);
+}
diff --git a/cprogs/smtpallow.o b/cprogs/smtpallow.o
new file mode 100644 (file)
index 0000000..3d66f7a
Binary files /dev/null and b/cprogs/smtpallow.o differ
diff --git a/cprogs/smtpallow.so b/cprogs/smtpallow.so
new file mode 100755 (executable)
index 0000000..3fa3346
Binary files /dev/null and b/cprogs/smtpallow.so differ
diff --git a/cprogs/usernice.c b/cprogs/usernice.c
new file mode 100644 (file)
index 0000000..1f05e19
--- /dev/null
@@ -0,0 +1,67 @@
+/**/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <pwd.h>
+#include <sys/resource.h>
+
+int main(int argc,char **argv) {
+  long l;
+  int mrenice,wrenice,newprio,eflag;
+  uid_t ruid;
+  char *ep;
+  struct passwd *pw;
+
+  mrenice=0;
+  if (argc < 3) {
+    fputs("usernice: too few args\n"
+          " usage: usernice <nicelevel> <command> <arguments>\n"
+          "        usernice <nicelevel>p <pid> <pid> ...\n"
+          "        usernice <nicelevel>u <username|uid> ...\n",
+          stderr);
+    exit(-1);
+  }
+  l= strtol(*++argv,&ep,10);
+  if (*ep == 'p' || *ep == 'u') { mrenice= *ep++; }
+  if (*ep) { fputs("usernice: priority not numeric or bad flags\n",stderr); exit(-1); }
+  if (l<-20 || l>20)
+    { fputs("usernice: priority must be -20 .. 20\n",stderr); exit(-1); }
+  newprio= l;
+  if (mrenice) {
+    eflag=0;
+    while (*++argv) {
+      if (mrenice == 'p') {
+        wrenice= PRIO_PROCESS;
+        l= strtoul(*argv,&ep,10);
+        if (*ep) {
+          fprintf(stderr,"usernice: pid `%s' not numeric\n",*argv); eflag=2;
+          continue;
+        }
+      } else {
+        wrenice= PRIO_USER;
+        l= strtoul(*argv,&ep,10);
+        if (*ep) {
+          pw= getpwnam(*argv);
+          if (!pw) {
+            fprintf(stderr,"usernice: unknown user `%s'\n",*argv); eflag=2;
+            continue;
+          }
+          l= pw->pw_uid;
+        }
+      }
+      if (setpriority(wrenice,l,newprio)) {
+        perror(*argv); if (!eflag) eflag=1;
+      }
+    }
+    exit(eflag);
+  } else {
+    if (setpriority(PRIO_PROCESS,0,newprio))
+      { perror("usernice: setpriority"); exit(-1); }
+    ruid= getuid(); if (ruid == (uid_t)-1) { perror("usernice: getuid"); exit(-1); }
+    if (setreuid(ruid,ruid)) { perror("usernice: setreuid"); exit(-1); }
+    execvp(argv[1],argv+1); perror("usernice: exec"); exit(-1);
+  }
+}
diff --git a/cprogs/usr-local-src-misc-Makefile b/cprogs/usr-local-src-misc-Makefile
new file mode 100644 (file)
index 0000000..a1a96f2
--- /dev/null
@@ -0,0 +1,18 @@
+CFLAGS=        -Wall -Wwrite-strings -Wmissing-prototypes -Wstrict-prototypes \
+       -Wpointer-arith -O2 -g -DREALLY_CHECK_FILE='"/etc/inittab"'
+LDFLAGS=
+
+TARGETS=really
+
+all:           $(TARGETS)
+
+really:                really.o myopt.o
+
+really-test:   really Makefile
+               rm -f really-test
+               cp really really-test
+               really chown root.staff really-test
+               really chmod 4770 really-test
+
+really-check:  really-test really.testcases
+               ./really.testcases
diff --git a/cprogs/usr-local-src-misc-Makefile~ b/cprogs/usr-local-src-misc-Makefile~
new file mode 100644 (file)
index 0000000..edac912
--- /dev/null
@@ -0,0 +1,9 @@
+CFLAGS=        -Wall -Wwrite-strings -Wmissing-prototypes -Wstrict-prototypes \
+       -Wpointer-arith -O2 -g -DREALLY_CHECK_FILE='"/etc/inittab"'
+LDFLAGS=
+
+TARGETS=really
+
+all:           $(TARGETS)
+
+really:                really.o myopt.o
index 56742a8..2574dfd 100644 (file)
@@ -1,6 +1,11 @@
 chiark-utils (3.99.1.0.2) unstable; urgency=low
 
   * foreign zones checked from delegation by default.
+  * from chiark:/usr/local/src/misc/ (as found):
+    really (incl. myopt)
+    usernice
+    cvsweb-list
+    smtpallow
 
  --
 
diff --git a/scripts/cvsweb-list b/scripts/cvsweb-list
new file mode 100755 (executable)
index 0000000..b5ac819
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+print <<END or die $!;
+Content-Type: text/html
+
+<head>
+<title>chiark public CVS</title>
+<link rev="made" href="mailto:webmaster\@chiark.greenend.org.uk">
+</head>
+<body>
+<h1><img src="/chiark/icon90.gif" border="0" width="128" height="64"
+alt=""> chiark users' public CVS</h1>
+<ul>
+END
+
+open UL, "/etc/userlist" or die $!;
+while (<UL>) {
+    next if m/^\#/ or !m/\S/;
+    chomp($user= $_);
+    next unless readlink "/home/$user/public-cgi/cvsweb"
+       eq '/usr/local/lib/cvsweb';
+    $hd= 0;
+    $pc= "/home/$user/public-CVS/";
+    next unless opendir D, $pc;
+    while (defined($mod= readdir D)) {
+       next unless -d "$pc/$mod";
+       next if $mod =~ m/^\./;
+       if (!$hd) {
+           print "<li><A href=\"/ucgi/~$user/cvsweb\">$user</A>" or die $!;
+           print " (<A href=\"/~$user/\">homepage</A>)" or die $!
+               if -d "/home/$user/public-html";
+           print ":" or die $!;
+           $hd= 1;
+       } else {
+           print "," or die $!;
+       }
+       print " <A href=\"/ucgi/~$user/cvsweb/$mod/\">$mod</A>" or die $!;
+    }
+    next unless $hd;
+    print "</li>\n" or die $!;
+}
+
+close UL or die $!;
+
+print <<END or die $!;
+</ul>
+<hr>
+<ADDRESS>
+  maintained by
+  <A HREF="mailto:$ENV{SERVER_ADMIN}">$ENV{SERVER_ADMIN}</A>;
+  <A href="/">chiark home page</A>
+</ADDRESS>
+</body>
+END
+
+exit 0
diff --git a/scripts/cvsweb-list~ b/scripts/cvsweb-list~
new file mode 100755 (executable)
index 0000000..124235a
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+
+print <<END or die $!;
+Content-Type: text/html
+
+<head>
+<title>chiark public CVS</title>
+<link rev="made" href="mailto:webmaster\@chiark.greenend.org.uk">
+</head>
+<body>
+<h1>list of users exporting CVS repositories via cvsweb from chiark</h1>
+<ul>
+END
+
+open UL, "/etc/userlist" or die $!;
+while (<UL>) {
+    next if m/^\#/ or !m/\S/;
+    chomp($user= $_);
+    next unless readlink "/home/$user/public-cgi/cvsweb"
+       eq '/usr/local/lib/cvsweb';
+    $hd= 0;
+    $pc= "/home/$user/public-CVS/";
+    next unless opendir D, $pc;
+    while (defined($mod= readdir D)) {
+       next unless -d "$pc/$mod";
+       next if $mod =~ m/^\./;
+       if (!$hd) {
+           print "<li><A href=\"/ucgi/~$user/cvsweb\">$user</A>" or die $!;
+           print " (<A href=\"/~$user/\">homepage</A>)" or die $!
+               if -d "/home/$user/public-html";
+           print ":" or die $!;
+           $hd= 1;
+       } else {
+           print "," or die $!;
+       }
+       print " <A href=\"/ucgi/~$user/cvsweb/$mod/\">$mod</A>" or die $!;
+    }
+    next unless $hd;
+    print "</li>\n" or die $!;
+}
+
+close UL or die $!;
+
+print <<END or die $!;
+</ul>
+<hr>
+<ADDRESS>
+  maintained by
+  <A HREF="mailto:$ENV{SERVER_ADMIN}">$ENV{SERVER_ADMIN}</A>;
+  <A href="/">chiark home page</A>
+</ADDRESS>
+</body>
+END
+
+exit 0