RPM Package Manager, CVS Repository http://rpm5.org/cvs/ ____________________________________________________________________________ Server: rpm5.org Name: Jeff Johnson Root: /v/rpm/cvs Email: jbj@rpm5.org Module: rpm lua Date: 17-Aug-2008 20:31:37 Branch: HEAD Handle: 2008081718313402 Added files: lua/chkconfig chkconfig.c leveldb.c leveldb.h lua/local lshadow.c lshadow.h lwrs.c lwrs.h lua/shadow chkname.h commonio.c commonio.h config.h copydir.c defines.h faillog.h fputsx.c getdate.c getdate.h getdef.c getdef.h groupadd.c groupio.c groupio.h gshadow.c gshadow_.h list.c nscd.h prototypes.h pwauth.h pwio.c pwio.h sgetgrent.c sgetpwent.c sgroupio.c sgroupio.h shadowio.c shadowio.h strtoday.c useradd.c xmalloc.c Modified files: lua Makefile.am lualib.h rpm CHANGES rpm/rpmio rpmlua.c Log: - WR: add shadow/chkconfig internal lua modules. Summary: Revision Changes Path 1.20 +43 -0 lua/Makefile.am 1.1 +712 -0 lua/chkconfig/chkconfig.c 1.1 +740 -0 lua/chkconfig/leveldb.c 1.1 +55 -0 lua/chkconfig/leveldb.h 1.1 +142 -0 lua/local/lshadow.c 1.1 +7 -0 lua/local/lshadow.h 1.1 +140 -0 lua/local/lwrs.c 1.1 +7 -0 lua/local/lwrs.h 1.3 +0 -1 lua/lualib.h 1.1 +21 -0 lua/shadow/chkname.h 1.1 +945 -0 lua/shadow/commonio.c 1.1 +116 -0 lua/shadow/commonio.h 1.1 +412 -0 lua/shadow/config.h 1.1 +452 -0 lua/shadow/copydir.c 1.1 +351 -0 lua/shadow/defines.h 1.1 +61 -0 lua/shadow/faillog.h 1.1 +84 -0 lua/shadow/fputsx.c 1.1 +2575 -0 lua/shadow/getdate.c 1.1 +14 -0 lua/shadow/getdate.h 1.1 +419 -0 lua/shadow/getdef.c 1.1 +21 -0 lua/shadow/getdef.h 1.1 +647 -0 lua/shadow/groupadd.c 1.1 +201 -0 lua/shadow/groupio.c 1.1 +19 -0 lua/shadow/groupio.h 1.1 +474 -0 lua/shadow/gshadow.c 1.1 +77 -0 lua/shadow/gshadow_.h 1.1 +231 -0 lua/shadow/list.c 1.1 +18 -0 lua/shadow/nscd.h 1.1 +188 -0 lua/shadow/prototypes.h 1.1 +64 -0 lua/shadow/pwauth.h 1.1 +191 -0 lua/shadow/pwio.c 1.1 +19 -0 lua/shadow/pwio.h 1.1 +141 -0 lua/shadow/sgetgrent.c 1.1 +121 -0 lua/shadow/sgetpwent.c 1.1 +204 -0 lua/shadow/sgroupio.c 1.1 +20 -0 lua/shadow/sgroupio.h 1.1 +163 -0 lua/shadow/shadowio.c 1.1 +20 -0 lua/shadow/shadowio.h 1.1 +205 -0 lua/shadow/strtoday.c 1.1 +2008 -0 lua/shadow/useradd.c 1.1 +37 -0 lua/shadow/xmalloc.c 1.2519 +1 -0 rpm/CHANGES 2.57 +2 -0 rpm/rpmio/rpmlua.c ____________________________________________________________________________ patch -p0 <<'@@ .' Index: lua/Makefile.am ============================================================================ $ cvs diff -u -r1.19 -r1.20 Makefile.am --- lua/Makefile.am 20 May 2008 07:44:59 -0000 1.19 +++ lua/Makefile.am 17 Aug 2008 18:31:34 -0000 1.20 @@ -11,6 +11,10 @@ -I$(top_srcdir) \ -I$(srcdir)/local \ -I$(builddir)/local \ + -I$(srcdir)/chkconfig \ + -I$(builddir)/chkconfig \ + -I$(srcdir)/shadow \ + -I$(builddir)/shadow \ -I$(srcdir) rpmlua_SOURCES = lua.c @@ -37,8 +41,47 @@ local/lrexlib_lpcre.c \ local/lrexlib_lpcre_f.c \ local/lrexlib_lposix.c \ + local/lshadow.h \ + local/lshadow.c \ local/luuid.h \ local/luuid.c \ + local/lwrs.h \ + local/lwrs.c \ + shadow/chkname.h \ + shadow/commonio.h \ + shadow/commonio.c \ + shadow/config.h \ + shadow/copydir.c \ + shadow/defines.h \ + shadow/faillog.h \ + shadow/fputsx.c \ + shadow/getdate.h \ + shadow/getdate.c \ + shadow/getdef.h \ + shadow/getdef.c \ + shadow/groupadd.c \ + shadow/groupio.h \ + shadow/groupio.c \ + shadow/gshadow_.h \ + shadow/gshadow.c \ + shadow/list.c \ + shadow/nscd.h \ + shadow/prototypes.h \ + shadow/pwauth.h \ + shadow/pwio.h \ + shadow/pwio.c \ + shadow/sgroupio.h \ + shadow/sgroupio.c \ + shadow/sgetgrent.c \ + shadow/sgetpwent.c \ + shadow/shadowio.h \ + shadow/shadowio.c \ + shadow/strtoday.c \ + shadow/useradd.c \ + shadow/xmalloc.c \ + chkconfig/chkconfig.c \ + chkconfig/leveldb.h \ + chkconfig/leveldb.c \ linit.c \ lauxlib.h \ lauxlib.c \ @@ . patch -p0 <<'@@ .' Index: lua/chkconfig/chkconfig.c ============================================================================ $ cvs diff -u -r0 -r1.1 chkconfig.c --- /dev/null 2008-08-17 20:31:29 +0200 +++ chkconfig.c 2008-08-17 20:31:35 +0200 @@ -0,0 +1,712 @@ +/* + * This file was originally distributed as part of + * chkconfig-1.3.34-1.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* Copyright 1997-2006 Red Hat, Inc. + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <glob.h> +#include <libintl.h> +#include <locale.h> +#include <popt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +static char *progname; + +#define _(String) gettext((String)) + +#include "leveldb.h" + +static void usage(void) { +#if 0 + fprintf(stderr, _("%s version %s - Copyright (C) 1997-2000 Red Hat, Inc.\n"), progname, VERSION); +#endif + fprintf(stderr, _("This may be freely redistributed under the terms of " + "the GNU Public License.\n")); + fprintf(stderr, "\n"); + fprintf(stderr, _("usage: %s --list [name]\n"), progname); + fprintf(stderr, _(" %s --add <name>\n"), progname); + fprintf(stderr, _(" %s --del <name>\n"), progname); + fprintf(stderr, _(" %s --override <name>\n"), progname); + fprintf(stderr, _(" %s [--level <levels>] <name> %s\n"), progname, "<on|off|reset|resetpriorities>"); + +} + +static void readServiceError(int rc, char * name) { + if (rc == 2) { + fprintf(stderr, _("service %s supports chkconfig, but is not referenced in any runlevel (run 'chkconfig --add %s')\n"), name, name); + } else if (rc == 1) { + fprintf(stderr, _("service %s does not support chkconfig\n"), name); + } else { + fprintf(stderr, _("error reading information on service %s: %s\n"), + name, strerror(errno)); + } + + exit(1); +} + +static int delServiceOne(char *name, int level) { + int i, rc; + glob_t globres; + struct service s; + + if ((rc = readServiceInfo(name, &s, 0))) { + readServiceError(rc, name); + return 1; + } + if (s.type == TYPE_XINETD) return 0; + + + if (!findServiceEntries(name, level, &globres)) { + for (i = 0; i < globres.gl_pathc; i++) + unlink(globres.gl_pathv[i]); + if (globres.gl_pathc) globfree(&globres); + } + return 0; +} + +static int delService(char * name) { + int level, i, rc; + glob_t globres; + struct service s; + + if ((rc = readServiceInfo(name, &s, 0))) { + readServiceError(rc, name); + return 1; + } + if (s.type == TYPE_XINETD) return 0; + + for (level = 0; level < 7; level++) { + if (!findServiceEntries(name, level, &globres)) { + for (i = 0; i < globres.gl_pathc; i++) + unlink(globres.gl_pathv[i]); + if (globres.gl_pathc) globfree(&globres); + } + } + return 0; +} + + +static inline int laterThan(int i, int j) { + if (i <= j) { + i = j+1; + if (i > 99) + i = 99; + } + return i; +} + +static inline int earlierThan(int i, int j) { + if (i >= j) { + i = j -1; + if (i < 0) + i = 0; + } + return i; +} + +static int frobOneDependencies(struct service *s, struct service *servs, int numservs, int target) { + int i, j, k; + int s0 = s->sPriority; + int k0 = s->kPriority; + + if (s->sPriority < 0) s->sPriority = 50; + if (s->kPriority < 0) s->kPriority = 50; + for (i = 0; i < numservs ; i++) { + if (s->startDeps) { + for (j = 0; s->startDeps[j] ; j++) { + if (!strcmp(s->startDeps[j], servs[i].name)) + s->sPriority = laterThan(s->sPriority, servs[i].sPriority); + if (servs[i].provides) { + for (k = 0; servs[i].provides[k]; k++) { + if (!strcmp(s->startDeps[j], servs[i].provides[k])) + s->sPriority = laterThan(s->sPriority, servs[i].sPriority); + } + } + } + } + if (s->stopDeps) { + for (j = 0; s->stopDeps[j] ; j++) { + if (!strcmp(s->stopDeps[j], servs[i].name)) + s->kPriority = earlierThan(s->kPriority, servs[i].kPriority); + if (servs[i].provides) { + for (k = 0; servs[i].provides[k]; k++) { + if (!strcmp(s->stopDeps[j], servs[i].provides[k])) + s->kPriority = earlierThan(s->kPriority, servs[i].kPriority); + } + } + } + } + } + + if (target || ((s0 != s->sPriority) || (k0 != s->kPriority))) { + for (i = 0; i < 7; i++) { + if (isConfigured(s->name, i, NULL, NULL)) { + int on = isOn(s->name, i); + delServiceOne(s->name,i); + doSetService(*s, i, on); + } else if (target) { + delServiceOne(s->name,i); + doSetService(*s, i, ((1<<i) & s->levels)); + } + } + return 1; /* Resolved something */ + } + return 0; /* Didn't resolve anything */ +} + + +/* LSB-style dependency frobber. Calculates a usable start priority + * and stop priority. + * This algorithm will almost certainly break horribly at some point. */ +static void frobDependencies(struct service *s) { + DIR * dir; + struct dirent * ent; + struct stat sb; + struct service *servs = NULL; + int numservs = 0; + char fn[1024]; + int nResolved = 0; + + if (!(dir = opendir(RUNLEVELS "/init.d"))) { + fprintf(stderr, _("failed to open %s/init.d: %s\n"), RUNLEVELS, + strerror(errno)); + return; + } + + while ((ent = readdir(dir))) { + const char *dn; + + /* Skip any file starting with a . */ + if (ent->d_name[0] == '.') continue; + + /* Skip files with known bad extensions */ + if ((dn = strrchr(ent->d_name, '.')) != NULL && + (!strcmp(dn, ".rpmsave") || !strcmp(dn, ".rpmnew") || !strcmp(dn, ".rpmorig") || !strcmp(dn, ".swp"))) + continue; + + dn = ent->d_name + strlen(ent->d_name) - 1; + if (*dn == '~' || *dn == ',') + continue; + + sprintf(fn, RUNLEVELS "/init.d/%s", ent->d_name); + if (stat(fn, &sb)) { + continue; + } + if (!S_ISREG(sb.st_mode)) continue; + if (!strcmp(ent->d_name, s->name)) continue; + servs = realloc(servs, (numservs+1) * sizeof(struct service)); + if (!readServiceInfo(ent->d_name, servs + numservs, 0)) + numservs++; + } + + /* Resolve recursively the other dependancies */ + do { + nResolved = 0; + int i; + + for (i = 0; i < numservs ; i++) { + if ((servs+i)->isLSB) + nResolved += frobOneDependencies(servs+i, servs, numservs, 0); + } + } while (nResolved); + + /* Resolve our target */ + frobOneDependencies(s, servs, numservs, 1); +} + +static int addService(char * name) { + int i, rc; + struct service s; + + if ((rc = readServiceInfo(name, &s, 0))) { + readServiceError(rc, name); + return 1; + } + + if (s.type == TYPE_XINETD) return 0; + if (s.isLSB) + frobDependencies(&s); + else + for (i = 0; i < 7; i++) { + if (!isConfigured(name, i, NULL, NULL)) { + if ((1 << i) & s.levels) + doSetService(s, i, 1); + else + doSetService(s, i, 0); + } + } + + return 0; +} + +static int overrideService(char * name) { + /* Apply overrides if available; no available overrides is no error */ + int level, i, rc; + glob_t globres; + struct service s; + struct service o; + int priority; + char type; + int doChange = 1; + int configured = 0; + int thisLevelAdded, thisLevelOn; + + if ((rc = readServiceDifferences(name, &s, &o, 0))) { + return 0; + } + + if (s.type == TYPE_XINETD) return 0; + + if ((s.levels == o.levels) && + (s.kPriority == o.kPriority) && + (s.sPriority == o.sPriority)) { + /* no relevant changes in the override file */ + return 0; + } + + if (s.isLSB && (s.sPriority <= -1) && (s.kPriority <= -1)) + frobDependencies(&s); + if ((s.isLSB || o.isLSB) && (o.sPriority <= -1) && (o.kPriority <= -1)) + frobDependencies(&o); + + /* Apply overrides only if the service has not been changed since + * being added, and not if the service has never been configured + * at all. + */ + + for (level = 0; level < 7; level++) { + thisLevelAdded = isConfigured(name, level, &priority, &type); + thisLevelOn = s.levels & 1<<level; + if (thisLevelAdded) { + configured = 1; + if (type == 'S') { + if (priority != s.sPriority || !thisLevelOn) { + doChange = 0; + break; + } + } else if (type == 'K') { + if (priority != s.kPriority || thisLevelOn) { + doChange = 0; + break; + } + } + } + } + + if (configured && doChange) { + for (level = 0; level < 7; level++) { + if (!findServiceEntries(name, level, &globres)) { + for (i = 0; i < globres.gl_pathc; i++) + unlink(globres.gl_pathv[i]); + if (globres.gl_pathc) + globfree(&globres); + if ((1 << level) & o.levels) + doSetService(o, level, 1); + else + doSetService(o, level, 0); + } + } + } + + return 0; +} + + +static int showServiceInfo(char * name, int forgiving) { + int rc; + int i; + struct service s; + + rc = readServiceInfo(name, &s, 0); + + if (!rc && s.type == TYPE_INIT_D) { + rc = 2; + for (i = 0 ; i < 7 ; i++) { + if (isConfigured(name, i, NULL, NULL)) { + rc = 0; + break; + } + } + } + + if (rc) { + if (!forgiving) + readServiceError(rc, name); + return forgiving ? 0 : 1; + } + + printf("%-15s", s.name); + if (s.type == TYPE_XINETD) { + printf("\t%s\n", s.levels ? _("on") : _("off")); + return 0; + } + + for (i = 0; i < 7; i++) { + printf("\t%d:%s", i, isOn(s.name, i) ? _("on") : _("off")); + } + printf("\n"); + + return 0; +} + +static int isXinetdEnabled() { + int i; + struct service s; + + if (readServiceInfo("xinetd", &s, 0)) { + return 0; + } + for (i = 0; i < 7; i++) { + if (isOn("xinetd", i)) + return 1; + } + return 0; +} + +static int serviceNameCmp(const void * a, const void * b) { + return strcmp(* (char **)a, * (char **)b); +} + +static int xinetdNameCmp(const void * a, const void * b) { + const struct service * first = a; + const struct service * second = b; + + return strcmp(first->name, second->name); +} + + + +static int listService(char * item) { + DIR * dir; + struct dirent * ent; + struct stat sb; + char fn[1024]; + char **services; + int i; + int numServices = 0; + int numServicesAlloced; + int err = 0; + + if (item) return showServiceInfo(item, 0); + + numServicesAlloced = 10; + services = malloc(sizeof(*services) * numServicesAlloced); + + if (!(dir = opendir(RUNLEVELS "/init.d"))) { + fprintf(stderr, _("failed to open %s/init.d: %s\n"), RUNLEVELS, + strerror(errno)); + return 1; + } + + while ((ent = readdir(dir))) { + const char *dn; + + /* Skip any file starting with a . */ + if (ent->d_name[0] == '.') continue; + + /* Skip files with known bad extensions */ + if ((dn = strrchr(ent->d_name, '.')) != NULL && + (!strcmp(dn, ".rpmsave") || !strcmp(dn, ".rpmnew") || !strcmp(dn, ".rpmorig") || !strcmp(dn, ".swp"))) + continue; + + dn = ent->d_name + strlen(ent->d_name) - 1; + if (*dn == '~' || *dn == ',') + continue; + + sprintf(fn, RUNLEVELS "/init.d/%s", ent->d_name); + if (stat(fn, &sb)) { + fprintf(stderr, _("error reading info for service %s: %s\n"), + ent->d_name, strerror(errno)); + continue; + } + if (!S_ISREG(sb.st_mode)) continue; + + if (numServices == numServicesAlloced) { + numServicesAlloced += 10; + services = realloc(services, numServicesAlloced * sizeof(*services)); + } + + services[numServices] = alloca(strlen(ent->d_name) + 1); + strncpy(services[numServices++], ent->d_name, strlen(ent->d_name) + 1); + } + + qsort(services, numServices, sizeof(*services), serviceNameCmp); + + for (i = 0; i < numServices ; i++) { + if (showServiceInfo(services[i], 1)) { + free(services); + closedir(dir); + return 1; + } + } + + free(services); + + closedir(dir); + + if (isXinetdEnabled()) { + struct service *s, *t; + + printf("\n"); + printf(_("xinetd based services:\n")); + if (!(dir = opendir(XINETDDIR))) { + fprintf(stderr, _("failed to open directory %s: %s\n"), + XINETDDIR, strerror(err)); + return 1; + } + numServices = 0; + numServicesAlloced = 10; + s = malloc(sizeof (*s) * numServicesAlloced); + + while ((ent = readdir(dir))) { + const char *dn; + + /* Skip any file starting with a . */ + if (ent->d_name[0] == '.') continue; + + /* Skip files with known bad extensions */ + if ((dn = strrchr(ent->d_name, '.')) != NULL && + (!strcmp(dn, ".rpmsave") || !strcmp(dn, ".rpmnew") || !strcmp(dn, ".rpmorig") || !strcmp(dn, ".swp"))) + continue; + + dn = ent->d_name + strlen(ent->d_name) - 1; + if (*dn == '~' || *dn == ',') + continue; + + if (numServices == numServicesAlloced) { + numServicesAlloced += 10; + s = realloc(s, numServicesAlloced * sizeof (*s)); + } + if (readXinetdServiceInfo(ent->d_name, s + numServices, 0) != -1) + numServices ++; + } + + qsort(s, numServices, sizeof(*s), xinetdNameCmp); + t = s; + for (i = 0; i < numServices; i++, s++) { + char *tmp = malloc(strlen(s->name) + 5); + sprintf(tmp,"%s:",s->name); + printf("\t%-15s\t%s\n", tmp, s->levels ? _("on") : _("off")); + } + closedir(dir); + free(t); + } + return 0; +} + +int setService(char * name, int where, int state) { + int i, rc; + int what; + struct service s; + + if (!where && state != -1) { + /* levels 2, 3, 4, 5 */ + where = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5); + } else if (!where) { + where = (1 << 0) | (1 << 1) | (1 << 2) | + (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); + } + + if ((rc = readServiceInfo(name, &s, 0))) { + readServiceError(rc, name); + return 1; + } + + if (s.type == TYPE_INIT_D) { + int rc = 0; + + if (s.isLSB) + frobDependencies(&s); + for (i = 0; i < 7; i++) { + + if (!((1 << i) & where)) continue; + + if (state == 1 || state == 0) + what = state; + else if (state == -2) + what = isOn(name, i); + else if (s.levels & (1 << i)) + what = 1; + else + what = 0; + rc |= doSetService(s, i, what); + } + return rc; + } else if (s.type == TYPE_XINETD) { + if (setXinetdService(s, state)) { + return 1; + } + system("/etc/init.d/xinetd reload >/dev/null 2>&1"); + } + + return 0; +} + +int chkconfig_main(int argc, char ** argv) { + int listItem = 0, addItem = 0, delItem = 0, overrideItem = 0; + int rc, i, x; + int LSB = 0; + char * levels = NULL; + int help=0, version=0; + struct service s; + poptContext optCon; + struct poptOption optionsTable[] = { + { "add", '\0', 0, &addItem, 0 }, + { "del", '\0', 0, &delItem, 0 }, + { "override", '\0', 0, &overrideItem, 0 }, + { "list", '\0', 0, &listItem, 0 }, + { "level", '\0', POPT_ARG_STRING, &levels, 0 }, + { "levels", '\0', POPT_ARG_STRING, &levels, 0 }, + { "help", 'h', POPT_ARG_NONE, &help, 0 }, + { "version", 'v', POPT_ARG_NONE, &version, 0 }, + { 0, 0, 0, 0, 0 } + }; + + if ((progname = strrchr(argv[0], '/')) != NULL) + progname++; + else + progname = argv[0]; + if (!strcmp(progname,"install_initd")) { + addItem++; + LSB++; + } + if (!strcmp(progname,"remove_initd")) { + delItem++; + LSB++; + } + +#if 0 + setlocale(LC_ALL, ""); + bindtextdomain("chkconfig","/usr/share/locale"); + textdomain("chkconfig"); +#endif + + optCon = poptGetContext("chkconfig", argc, argv, optionsTable, 0); + poptReadDefaultConfig(optCon, 1); + + if ((rc = poptGetNextOpt(optCon)) < -1) { + fprintf(stderr, "%s: %s\n", + poptBadOption(optCon, POPT_BADOPTION_NOALIAS), + poptStrerror(rc)); + return 1; + } + + if (version) { + fprintf(stdout, _("%s version %s\n"), progname, "no version!"); + return 0; + } + + if (help || argc == 1) { usage(); return 1; } + + if ((listItem + addItem + delItem + overrideItem) > 1) { + fprintf(stderr, _("only one of --list, --add, --del, or --override" + " may be specified\n")); + return 1; + } + + if (addItem) { + char * name = (char *)poptGetArg(optCon); + + if (!name || !*name || poptGetArg(optCon)) + { usage(); return 1; } + + if (LSB) + name = basename(name); + return addService(name); + } else if (delItem) { + char * name = (char *)poptGetArg(optCon); + + if (!name || !*name || poptGetArg(optCon)) { usage(); return 1; } + + if (LSB) + name = basename(name); + return delService(name); + } else if (overrideItem) { + char * name = (char *)poptGetArg(optCon); + + if (!name || !*name || poptGetArg(optCon)) { usage(); return 1; } + + name = basename(name); + return overrideService(name); + } else if (listItem) { + char * item = (char *)poptGetArg(optCon); + + if (item && poptGetArg(optCon)) { usage(); return 1; } + + return listService(item); + } else { + char * name = (char *)poptGetArg(optCon); + char * state = (char *)poptGetArg(optCon); + int where = 0, level = -1; + + if (!name) { + usage(); + return 1; + } + if (levels) { + where = parseLevels(levels, 0); + if (where == -1) { usage(); return 1; } + } + + if (!state) { + if (where) { + rc = x = 0; + i = where; + while (i) { + if (i & 1) { + rc++; + level = x; + } + i >>= 1; + x++; + } + + if (rc > 1) { + fprintf(stderr, _("only one runlevel may be specified for " + "a chkconfig query\n")); + return 1; + } + } + rc = readServiceInfo(name, &s, 0); + if (rc) + return 1; + if (s.type == TYPE_XINETD) { + if (isOn("xinetd",level)) + return !s.levels; + else + return 1; + } else + return isOn(name, level) ? 0 : 1; + } else if (!strcmp(state, "on")) + return setService(name, where, 1); + else if (!strcmp(state, "off")) + return setService(name, where, 0); + else if (!strcmp(state, "reset")) + return setService(name, where, -1); + else if (!strcmp(state, "resetpriorities")) + return setService(name, where, -2); + else + { usage(); return 1; } + } + + usage(); + + return 1; +} @@ . patch -p0 <<'@@ .' Index: lua/chkconfig/leveldb.c ============================================================================ $ cvs diff -u -r0 -r1.1 leveldb.c --- /dev/null 2008-08-17 20:31:29 +0200 +++ leveldb.c 2008-08-17 20:31:35 +0200 @@ -0,0 +1,740 @@ +/* + * This file was originally distributed as part of + * chkconfig-1.3.34-1.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* Copyright 1997-2006 Red Hat, Inc. + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <alloca.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <glob.h> +#include <libintl.h> +#include <locale.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +/* Changes + 1998-09-22 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> + i18n for init.d scripts (eg.: description(pt_BR) is a brazilian + portuguese description for the package) +*/ + +#define _(String) gettext((String)) + +#include "leveldb.h" + +int parseLevels(char * str, int emptyOk) { + char * chptr = str; + int rc = 0; + + if (!str || !strlen(str)) + return emptyOk ? 0 : -1; + + while (*chptr) { + if (!isdigit(*chptr) || *chptr > '6') return -1; + rc |= 1 << (*chptr - '0'); + chptr++; + } + + return rc; +} + +int readDescription(char *start, char *bufstop, char **english_desc, char **serv_desc) { + char english; + char my_lang_loaded = 0; + char is_my_lang = 0; + char * lang = getenv ("LANG"); + char * final_parenthesis; + char * end, *next; + int i; + + english = *start == ':'; + end = strchr(start, '\n'); + if (!end) + next = end = bufstop; + else + next = end + 1; + + if (!english) { + if (*start != '(') { + return 1; + } + + ++start; + final_parenthesis = strchr (start, ')'); + + if (final_parenthesis == NULL || final_parenthesis - start > 5) { + return 1; + } + + is_my_lang = lang ? strncmp (lang, start, strlen (lang)) == 0 : 0; + start = final_parenthesis + 2; + } else ++start; + + while (isspace(*start) && start < end) start++; + if (start == end) { + return 1; + } + { + char* desc = malloc(end - start + 1); + strncpy(desc, start, end - start); + desc[end - start] = '\0'; + + start = next; + + while (desc[strlen(desc) - 1] == '\\') { + desc[strlen(desc) - 1] = '\0'; + start = next; + + while (isspace(*start) && start < bufstop) start++; + if (start == bufstop || *start != '#') { + return 1; + } + + start++; + + while (isspace(*start) && start < bufstop) start++; + if (start == bufstop) { + return 1; + } + + end = strchr(start, '\n'); + if (!end) + next = end = bufstop; + else + next = end + 1; + + i = strlen(desc); + desc = realloc(desc, i + end - start + 1); + strncat(desc, start, end - start); + desc[i + end - start] = '\0'; + + start = next; + } + + if (desc) { + if (my_lang_loaded) { + free(desc); + } else if (is_my_lang) { + if (*serv_desc) + free(*serv_desc); + + *serv_desc = desc; + return 0; + } else if (english) { + if (*serv_desc) + free(*serv_desc); + + if (*english_desc) + free (*english_desc); + + *english_desc = desc; + } else free (desc); + } + } + return 0; +} + +int readXinetdServiceInfo(char *name, struct service * service, int honorHide) { + char * filename = alloca(strlen(name) + strlen(XINETDDIR) + 50); + int fd; + struct service serv = { + name: NULL, + levels: -1, + kPriority: -1, + sPriority: -1, + desc: NULL, + startDeps: NULL, + stopDeps: NULL, + provides: NULL, + type: TYPE_XINETD, + isLSB: 0, + enabled: -1 + }; + struct stat sb; + char * buf, *ptr; + char * eng_desc = NULL, *start; + + snprintf(filename, strlen(name)+strlen(XINETDDIR)+50, XINETDDIR "/%s", name); + + if ((fd = open(filename, O_RDONLY)) < 0) return -1; + fstat(fd,&sb); + if (! S_ISREG(sb.st_mode)) return -1; + buf = malloc(sb.st_size+1); + if (read(fd,buf,sb.st_size)!=sb.st_size) { + close(fd); + free(buf); + return -1; + } + close(fd); + serv.name = strdup(name); + buf[sb.st_size] = '\0'; + start = buf; + while (buf) { + ptr = strchr(buf,'\n'); + if (*buf == '#') { + buf++; + while (isspace(*buf) && buf < ptr) buf++; + if (!strncmp(buf,"default:", 9)) { + buf+=8; + while(isspace(*buf)) buf++; + if (!strncmp(buf+9,"on",2)) { + serv.enabled = 1; + } else { + serv.enabled = 0; + } + } else if (!strncmp(buf,"description:",12)) { + buf+=11; + if (readDescription(buf,start+sb.st_size, + &serv.desc,&eng_desc)) { + if (serv.desc) free(serv.desc); + } + if (!serv.desc) { + if (eng_desc) + serv.desc = eng_desc; + } else if (eng_desc) + free (eng_desc); + } + if (ptr) { + *ptr = '\0'; + ptr++; + } + buf = ptr; + continue; + } + while (isspace(*buf) && buf < ptr) buf++; + if (!strncmp(buf,"disable", 7)) { + buf = strstr(buf,"="); + if (buf) + do { + buf++; + } while(isspace(*buf)); + + if (buf && strncmp(buf,"yes",3)) { + serv.levels = parseLevels("0123456",0); + if (serv.enabled == -1) + serv.enabled = 1; + } else { + serv.levels = 0; + if (serv.enabled == -1) + serv.enabled = 0; + } + } + if (ptr) { + *ptr = '\0'; + ptr++; + } + buf = ptr; + } + *service = serv; + return 0; +} + +int readServiceInfo(char * name, struct service * service, int honorHide) { + char * filename = alloca(strlen(name) + strlen(RUNLEVELS) + 50); + int fd; + struct service serv, serv_overrides; + int parseret; + + sprintf(filename, RUNLEVELS "/init.d/%s", name); + + if ((fd = open(filename, O_RDONLY)) < 0) { + return readXinetdServiceInfo(name,service,honorHide); + } + + parseret = parseServiceInfo(fd, name, &serv, honorHide, 0); + if (parseret) { + return parseret; + } + + sprintf(filename, RUNLEVELS "/chkconfig.d/%s", name); + if ((fd = open(filename, O_RDONLY)) >= 0) { + parseret = parseServiceInfo(fd, name, &serv_overrides, honorHide, 1); + if (parseret >= 0) { + if (serv_overrides.name) serv.name = serv_overrides.name; + if (serv_overrides.levels != -1) serv.levels = serv_overrides.levels; + if (serv_overrides.kPriority != -2) serv.kPriority = serv_overrides.kPriority; + if (serv_overrides.sPriority != -2) serv.sPriority = serv_overrides.sPriority; + if (serv_overrides.desc) serv.desc = serv_overrides.desc; + if (serv_overrides.startDeps) serv.startDeps = serv_overrides.startDeps; + if (serv_overrides.stopDeps) serv.stopDeps = serv_overrides.stopDeps; + if (serv_overrides.provides) serv.provides = serv_overrides.provides; + if (serv_overrides.isLSB || serv.isLSB) serv.isLSB = 1; + } + } + + *service = serv; + return 0; +} + +int readServiceDifferences(char * name, struct service * service, struct service * service_overrides, int honorHide) { + char * filename = alloca(strlen(name) + strlen(RUNLEVELS) + 50); + int fd; + struct service serv, serv_overrides; + int parseret; + + sprintf(filename, RUNLEVELS "/init.d/%s", name); + + if ((fd = open(filename, O_RDONLY)) < 0) { + return readXinetdServiceInfo(name,service,honorHide); + } + + parseret = parseServiceInfo(fd, name, &serv, honorHide, 0); + if (parseret) { + return parseret; + } + + sprintf(filename, RUNLEVELS "/chkconfig.d/%s", name); + if ((fd = open(filename, O_RDONLY)) >= 0) { + parseret = parseServiceInfo(fd, name, &serv_overrides, honorHide, 1); + } else { + return 1; + } + if (parseret) { + return 1; + } + + *service = serv; + *service_overrides = serv_overrides; + return 0; +} + + +int parseServiceInfo(int fd, char * name, struct service * service, int honorHide, int partialOk) { + struct stat sb; + char * bufstart, * bufstop, * start, * end, * next, *tmpbufstart; + struct service serv = { + name: NULL, + levels: -1, + kPriority: -1, + sPriority: -1, + desc: NULL, + startDeps: NULL, + stopDeps: NULL, + provides: NULL, + type: TYPE_INIT_D, + isLSB: 0, + enabled: 0 + }; + char overflow; + char levelbuf[20]; + char * english_desc = NULL; + + fstat(fd, &sb); + + bufstart = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (bufstart == ((caddr_t) -1)) { + close(fd); + return -1; + } + + tmpbufstart = (char*)malloc(sb.st_size+1); + if (tmpbufstart == NULL) { + close(fd); + return -1; + } + + memcpy(tmpbufstart, bufstart, sb.st_size); + munmap(bufstart, sb.st_size); + + bufstart = tmpbufstart; + bufstop = bufstart + sb.st_size; + *bufstop = 0; + + close(fd); + + next = bufstart; + while (next < bufstop && (serv.levels == -1 || !serv.desc)) { + start = next; + + while (isspace(*start) && start < bufstop) start++; + if (start == bufstop) break; + + end = strchr(start, '\n'); + if (!end) + next = end = bufstop; + else + next = end + 1; + + if (*start != '#') continue; + + start++; + if (!strncmp(start, "## BEGIN INIT INFO", 18)) + serv.isLSB = 1; + + while (isspace(*start) && start < end) start++; + if (start == end) continue; + if (honorHide && !strncmp(start, "hide:", 5)) { + start += 5; + while (isspace(*start) && start < end) start++; + if (start == end || !strncmp(start, "true", 4)) { + if (serv.desc) free(serv.desc); + free(bufstart); + return 1; + } + } + + if (!strncmp(start, "chkconfig:", 10)) { + int spri, kpri; + + start += 10; + while (isspace(*start) && start < end) start++; + if (start == end) { + if (serv.desc) free(serv.desc); + free(bufstart); + return 1; + } + + if ((sscanf(start, "%s %d %d%c", levelbuf, + &spri, &kpri, &overflow) != 4) || + !isspace(overflow)) { + if (serv.desc) free(serv.desc); + free(bufstart); + return 1; + } + if (spri > 99 || kpri > 99 || kpri < 0 || spri < 0) { + if (serv.desc) free(serv.desc); + free(bufstart); + return 1; + } + if (serv.sPriority == -1) + serv.sPriority = spri; + if (serv.kPriority == -1) + serv.kPriority = kpri; + + if (serv.levels == -1) { + if (!strcmp(levelbuf, "-")) + serv.levels = 0; + else + serv.levels = parseLevels(levelbuf, 0); + } + if (serv.levels == -1) { + if (serv.desc) free(serv.desc); + free(bufstart); + return 1; + } + } else if (!strncmp(start, "description", 11) || + !strncmp(start, "Description:", 12) || + !strncmp(start, "Short-Description:", 18)) { + if (readDescription(start+11, bufstop, &english_desc, &serv.desc)) { + if (serv.desc) free(serv.desc); + } + } else if (!strncmp(start, "Default-Start:", 14)) { + char *t; + + start+=14; + while (1) { + int lev; + + lev = strtol(start, &t, 10); + if (t && t != start) + start = t; + else + break; + if (serv.levels == -1) + serv.levels = 0; + serv.levels |= 1 << lev; + } + } else if (!strncmp(start, "Default-Stop:", 13)) { + char *t; + + start+=13; + while (1) { + int lev; + + lev = strtol(start, &t, 10); + if (t && t != start) + start = t; + else + break; + if (serv.levels == -1) + serv.levels = 0; + serv.levels &= ~(1 << lev); + } + } else if (!strncmp(start, "Required-Start:", 15)) { + char *t; + int numdeps = 0; + + start+=15; + while (1) { + while (*start && isspace(*start) && start < end) start++; + if (start == end) + break; + t = start; + while (*t && !isspace(*t) && t < end) t++; + if (isspace(*t)) { + *t = '\0'; + t++; + } + numdeps++; + serv.startDeps = realloc(serv.startDeps, + (numdeps + 1) * sizeof(char *)); + serv.startDeps[numdeps-1] = strdup(start); + serv.startDeps[numdeps] = NULL; + if (!t || t >= end) + break; + else + start = t; + } + } else if (!strncmp(start, "Required-Stop:", 14)) { + char *t; + int numdeps = 0; + + start+=14; + while (1) { + while (*start && isspace(*start) && start < end) start++; + if (start == end) + break; + t = start; + while (*t && !isspace(*t) && t < end) t++; + if (isspace(*t)) { + *t = '\0'; + t++; + } + numdeps++; + serv.stopDeps = realloc(serv.stopDeps, + (numdeps + 1) * sizeof(char *)); + serv.stopDeps[numdeps-1] = strdup(start); + serv.stopDeps[numdeps] = NULL; + if (!t || t >= end) + break; + else + start = t; + } + } else if (!strncmp(start, "Provides:", 9)) { + char *t; + int numdeps = 0; + + start+=9; + while (1) { + while (*start && isspace(*start) && start < end) start++; + if (start == end) + break; + t = start; + while (*t && !isspace(*t) && t < end) t++; + if (isspace(*t)) { + *t = '\0'; + t++; + } + numdeps++; + serv.provides = realloc(serv.provides, + (numdeps + 1) * sizeof(char *)); + serv.provides[numdeps-1] = strdup(start); + serv.provides[numdeps] = NULL; + if (!t || t >= end) + break; + else + start = t; + } + + } + } + + free(bufstart); + + if (!serv.desc) { + if (english_desc) + serv.desc = english_desc; + } else if (english_desc) + free (english_desc); + + if (!partialOk && ((serv.levels == -1) || !serv.desc)) { + return 1; + } + + serv.name = strdup(name); + if (!serv.provides) { + serv.provides = malloc(2 * sizeof(char *)); + serv.provides[0] = strdup(name); + serv.provides[1] = NULL; + } + + *service = serv; + return 0; +} + +/* returns -1 on error */ +int currentRunlevel(void) { + FILE * p; + char response[50]; + + p = popen("/sbin/runlevel", "r"); + if (!p) return -1; + + if (!fgets(response, sizeof(response), p)) { + pclose(p); + return -1; + } + + pclose(p); + + if (response[1] != ' ' || !isdigit(response[2]) || response[3] != '\n') + return -1; + + return response[2] - '0'; +} + +int findServiceEntries(char * name, int level, glob_t * globresptr) { + char match[200]; + glob_t globres; + int rc; + + sprintf(match, "%s/rc%d.d/[SK][0-9][0-9]%s", RUNLEVELS, level, name); + + rc = glob(match, GLOB_ERR | GLOB_NOSORT, NULL, &globres); + + if (rc && rc != GLOB_NOMATCH) { + fprintf(stderr, _("failed to glob pattern %s: %s\n"), match, + strerror(errno)); + return 1; + } else if (rc == GLOB_NOMATCH) { + globresptr->gl_pathc = 0; + return 0; + } + + *globresptr = globres; + return 0; +} + +int isConfigured(char * name, int level, int *priority, char *type) { + glob_t globres; + char *pri_string; + + if (findServiceEntries(name, level, &globres)) + exit(1); + + if (!globres.gl_pathc) + return 0; + + if (type) { + *type = globres.gl_pathv[0][11]; + } + + if (priority) { + pri_string = strndup(globres.gl_pathv[0]+12, 2); + if (!pri_string) return 0; + sscanf(pri_string, "%d", priority); + free(pri_string); + } + + globfree(&globres); + return 1; +} + +int isOn(char * name, int level) { + glob_t globres; + + if (level == -1) { + level = currentRunlevel(); + if (level == -1) { + fprintf(stderr, _("cannot determine current run level\n")); + return 0; + } + } + + if (findServiceEntries(name, level, &globres)) + exit(1); + + if (!globres.gl_pathc || !strstr(globres.gl_pathv[0], "/S")) + return 0; + + globfree(&globres); + return 1; +} + +int setXinetdService(struct service s, int on) { + int oldfd, newfd; + char oldfname[100], newfname[100]; + char tmpstr[50]; + char *buf, *ptr, *tmp; + struct stat sb; + + if (on == -1) { + on = s.enabled ? 1 : 0; + } + snprintf(oldfname,100,"%s/%s",XINETDDIR,s.name); + if ( (oldfd = open(oldfname,O_RDONLY)) == -1 ) { + return -1; + } + fstat(oldfd,&sb); + buf = malloc(sb.st_size+1); + if (read(oldfd,buf,sb.st_size)!=sb.st_size) { + close(oldfd); + free(buf); + return -1; + } + close(oldfd); + buf[sb.st_size] = '\0'; + snprintf(newfname,100,"%s/%s.XXXXXX",XINETDDIR,s.name); + newfd = mkstemp(newfname); + if (newfd == -1) { + free(buf); + return -1; + } + while (buf) { + tmp = buf; + ptr = strchr(buf,'\n'); + if (ptr) { + *ptr = '\0'; + ptr++; + } + while (isspace(*buf)) buf++; + if (strncmp(buf,"disable", 7) && strlen(buf)) { + write(newfd,tmp,strlen(tmp)); + write(newfd,"\n",1); + if (buf[0] == '{') { + snprintf(tmpstr,50,"\tdisable\t= %s", on ? "no" : "yes"); + write(newfd,tmpstr,strlen(tmpstr)); + write(newfd,"\n",1); + } + } + buf = ptr; + } + close(newfd); + chmod(newfname,0644); + unlink(oldfname); + return(rename(newfname,oldfname)); +} + +int doSetService(struct service s, int level, int on) { + int priority = on ? s.sPriority : s.kPriority; + char linkname[200]; + char linkto[200]; + glob_t globres; + int i; + + if (!findServiceEntries(s.name, level, &globres)) { + for (i = 0; i < globres.gl_pathc; i++) + unlink(globres.gl_pathv[i]); + if (globres.gl_pathc) globfree(&globres); + } + + sprintf(linkname, "%s/rc%d.d/%c%02d%s", RUNLEVELS, level, + on ? 'S' : 'K', priority, s.name); + sprintf(linkto, "../init.d/%s", s.name); + + unlink(linkname); /* just in case */ + if (symlink(linkto, linkname)) { + fprintf(stderr, _("failed to make symlink %s: %s\n"), linkname, + strerror(errno)); + return 1; + } + + return 0; +} + @@ . patch -p0 <<'@@ .' Index: lua/chkconfig/leveldb.h ============================================================================ $ cvs diff -u -r0 -r1.1 leveldb.h --- /dev/null 2008-08-17 20:31:29 +0200 +++ leveldb.h 2008-08-17 20:31:35 +0200 @@ -0,0 +1,55 @@ +/* + * This file was originally distributed as part of + * chkconfig-1.3.34-1.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* Copyright 1997-2006 Red Hat, Inc. + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef H_LEVELDB +#define H_LEVELDB + +#define RUNLEVELS "/etc/rc.d" +#define XINETDDIR "/etc/xinetd.d" + +#include <glob.h> + +#define TYPE_INIT_D 0 +#define TYPE_XINETD 1 + +struct service { + char * name; + int levels, kPriority, sPriority; + char * desc; + char **startDeps; + char **stopDeps; + char **provides; + int type; + int isLSB; + int enabled; +}; + +int parseLevels(char * str, int emptyOk); + +/* returns 0 on success, 1 if the service is not chkconfig-able, -1 if an + I/O error occurs (in which case errno can be checked) */ +int readServiceInfo(char * name, struct service * service, int honorHide); +int readServiceDifferences(char * name, struct service * service, struct service * service_overrides, int honorHide); +int parseServiceInfo(int fd, char * name, struct service * service, int honorHide, int partialOk); +int currentRunlevel(void); +int isOn(char * name, int where); +int isConfigured(char * name, int level, int *priority, char *type); +int doSetService(struct service s, int level, int on); +int findServiceEntries(char * name, int level, glob_t * globresptr); +int readXinetdServiceInfo(char *name, struct service *service, int honorHide); +int setXinetdService(struct service s, int on); + +#endif @@ . patch -p0 <<'@@ .' Index: lua/local/lshadow.c ============================================================================ $ cvs diff -u -r0 -r1.1 lshadow.c --- /dev/null 2008-08-17 20:31:29 +0200 +++ lshadow.c 2008-08-17 20:31:35 +0200 @@ -0,0 +1,142 @@ +/* +** $Id: lshadow.c,v 1.1 2008/08/17 18:31:35 jbj Exp $ +** Standard mathematical library +** See Copyright Notice in lua.h +*/ + + +#include <stdlib.h> +#include <math.h> +#include <string.h> + +#define lshadow_c + +#include "lua.h" + +#include "lauxlib.h" +#include "lshadow.h" + +extern int useradd_main (int argc, char **argv); +extern int chkconfig_main (int argc, char **argv); + +static int lcl_makeArgv(char *in, char **argv, int max) + { + int i; + char delim = ' '; + char *start = NULL; + char c; + + printf("Parsing [%s]\n", in); + + for ( i=0; i < max; ++i) + { + while (*in == ' ') ++in; /* skip spaces */ + if (!*in) return i; /* ignore traing spaces */ + if (*in == '"') delim = *in++; /* begin a quoted string */ + start = in; /* beginning of token */ + for ( c = *in; c != delim && c; c = *in) ++in; /* find end of token */ + *in++ = '\0'; /* mark end */ + *(argv+i) = start; /* might be 0 length! */ + if (!c) return i+1; /* end of input string */ + delim = ' '; + } + return -1; + } + +static int shadow_version (lua_State *L) + /*@globals internalState @*/ + /*@modifies L, internalState @*/ +{ + printf("version 6\n"); + return 0; +} + +static int shadow_groupadd (lua_State *L) + /*@globals internalState @*/ + /*@modifies L, internalState @*/ +{ + int argc; + char *argv[32]; /* yeah, well, this is big enough */ + char *cmdline; /* copy string from lua just to be safe */ + + argc = lua_gettop(L); /* number of arguments */ + if (argc != 1) return luaL_error(L, "One argument is required!"); + + cmdline = strdup(luaL_checklstring(L, 1, NULL)); /* we don't need the size */ + + argc = 1 + lcl_makeArgv(cmdline, argv+1, 31); + + argv[0] = "rpm_lua"; /* make up a program name */ + + useradd_main(argc, argv); + + free(cmdline); + return 0; +} + +static int shadow_useradd (lua_State *L) + /*@globals internalState @*/ + /*@modifies L, internalState @*/ +{ + int argc; + char *argv[32]; /* yeah, well, this is big enough */ + char *cmdline; /* copy string from lua just to be safe */ + + argc = lua_gettop(L); /* number of arguments */ + if (argc != 1) return luaL_error(L, "One argument is required!"); + + cmdline = strdup(luaL_checklstring(L, 1, NULL)); /* we don't need the size */ + + argc = 1 + lcl_makeArgv(cmdline, argv+1, 31); + + argv[0] = "rpm_lua"; /* make up a program name */ + + useradd_main(argc, argv); + + free(cmdline); + return 0; +} + +static int shadow_chkconfig (lua_State *L) + /*@globals internalState @*/ + /*@modifies L, internalState @*/ +{ + int argc; + char *argv[32]; /* yeah, well, this is big enough */ + char *cmdline; /* copy string from lua just to be safe */ + + argc = lua_gettop(L); /* number of arguments */ + if (argc != 1) return luaL_error(L, "One argument is required!"); + + cmdline = strdup(luaL_checklstring(L, 1, NULL)); /* we don't need the size */ + + argc = 1 + lcl_makeArgv(cmdline, argv+1, 31); + + argv[0] = "rpm_lua"; /* make up a program name */ + + chkconfig_main(argc, argv); + + free(cmdline); + return 0; +} + +/*@-readonlytrans@*/ +/*@unchecked@*/ +static const luaL_reg shadow[] = { + {"version", shadow_version}, + {"groupadd", shadow_groupadd}, + {"useradd", shadow_useradd}, + {"chkconfig", shadow_chkconfig}, + {NULL, NULL} +}; +/*@=readonlytrans@*/ + + +/* +** Open shadow library +*/ +LUALIB_API int luaopen_shadow (lua_State *L) { + luaL_openlib(L, "shadow", shadow, 0); + return 1; +} + @@ . patch -p0 <<'@@ .' Index: lua/local/lshadow.h ============================================================================ $ cvs diff -u -r0 -r1.1 lshadow.h --- /dev/null 2008-08-17 20:31:29 +0200 +++ lshadow.h 2008-08-17 20:31:35 +0200 @@ -0,0 +1,7 @@ +#ifndef LSHADOW_H +#define LSHADOW_H + +int luaopen_shadow(lua_State *L) + /*@modifies L @*/; + +#endif @@ . patch -p0 <<'@@ .' Index: lua/local/lwrs.c ============================================================================ $ cvs diff -u -r0 -r1.1 lwrs.c --- /dev/null 2008-08-17 20:31:29 +0200 +++ lwrs.c 2008-08-17 20:31:35 +0200 @@ -0,0 +1,140 @@ +/* +** $Id: lwrs.c,v 1.1 2008/08/17 18:31:35 jbj Exp $ +** WRLinux utilities +*/ + + +#include <stdlib.h> +#include <string.h> + +#define lwrs_c + +#include "lua.h" + +#include "lualib.h" +#include "lauxlib.h" +#include "lwrs.h" + +extern int useradd_main (int argc, char **argv); +extern int chkconfig_main (int argc, char **argv); + +static int lcl_makeArgv(char *in, char **argv, int max) + { + int i; + char delim = ' '; + char *start = NULL; + char c; + + printf("Creating argv from [%s]\n", in); + + for ( i=0; i < max; ++i) + { + while (*in == ' ') ++in; /* skip spaces */ + if (!*in) return i; /* ignore traing spaces */ + if (*in == '"') delim = *in++; /* begin a quoted string */ + start = in; /* beginning of token */ + for ( c = *in; c != delim && c; c = *in) ++in; /* find end of token */ + *in++ = '\0'; /* mark end */ + *(argv+i) = start; /* might be 0 length! */ + if (!c) return i+1; /* end of input string */ + delim = ' '; + } + return -1; + } + +static int wrs_version (lua_State *L) + /*@globals internalState @*/ + /*@modifies L, internalState @*/ +{ + printf("version 7\n"); + return 0; +} + +static int wrs_groupadd (lua_State *L) + /*@globals internalState @*/ + /*@modifies L, internalState @*/ +{ + int argc; + char *argv[32]; /* yeah, well, this is big enough */ + char *cmdline; /* copy string from lua just to be safe */ + + argc = lua_gettop(L); /* number of arguments */ + if (argc != 1) return luaL_error(L, "One argument is required!"); + + cmdline = strdup(luaL_checklstring(L, 1, NULL)); /* we don't need the size */ + + argc = 1 + lcl_makeArgv(cmdline, argv+1, 31); + + argv[0] = "rpm_lua"; /* make up a program name */ + + useradd_main(argc, argv); + + free(cmdline); + return 0; +} + +static int wrs_useradd (lua_State *L) + /*@globals internalState @*/ + /*@modifies L, internalState @*/ +{ + int argc; + char *argv[32]; /* yeah, well, this is big enough */ + char *cmdline; /* copy string from lua just to be safe */ + + argc = lua_gettop(L); /* number of arguments */ + if (argc != 1) return luaL_error(L, "One argument is required!"); + + cmdline = strdup(luaL_checklstring(L, 1, NULL)); /* we don't need the size */ + + argc = 1 + lcl_makeArgv(cmdline, argv+1, 31); + + argv[0] = "rpm_lua"; /* make up a program name */ + + useradd_main(argc, argv); + + free(cmdline); + return 0; +} + +static int wrs_chkconfig (lua_State *L) + /*@globals internalState @*/ + /*@modifies L, internalState @*/ +{ + int argc; + char *argv[32]; /* yeah, well, this is big enough */ + char *cmdline; /* copy string from lua just to be safe */ + + argc = lua_gettop(L); /* number of arguments */ + if (argc != 1) return luaL_error(L, "One argument is required!"); + + cmdline = strdup(luaL_checklstring(L, 1, NULL)); /* we don't need the size */ + + argc = 1 + lcl_makeArgv(cmdline, argv+1, 31); + + argv[0] = "rpm_lua"; /* make up a program name */ + + chkconfig_main(argc, argv); + + free(cmdline); + return 0; +} + +/*@-readonlytrans@*/ +/*@unchecked@*/ +static const luaL_reg wrs[] = { + {"version", wrs_version}, + {"groupadd", wrs_groupadd}, + {"useradd", wrs_useradd}, + {"chkconfig", wrs_chkconfig}, + {NULL, NULL} +}; +/*@=readonlytrans@*/ + + +/* +** Open wrs library +*/ +LUALIB_API int luaopen_wrs (lua_State *L) { + luaL_openlib(L, "wrs", wrs, 0); + return 1; +} @@ . patch -p0 <<'@@ .' Index: lua/local/lwrs.h ============================================================================ $ cvs diff -u -r0 -r1.1 lwrs.h --- /dev/null 2008-08-17 20:31:29 +0200 +++ lwrs.h 2008-08-17 20:31:35 +0200 @@ -0,0 +1,7 @@ +#ifndef LWRS_H +#define LWRS_H + +int luaopen_wrs(lua_State *L) + /*@modifies L @*/; + +#endif @@ . patch -p0 <<'@@ .' Index: lua/lualib.h ============================================================================ $ cvs diff -u -r1.2 -r1.3 lualib.h --- lua/lualib.h 25 Jan 2008 16:54:30 -0000 1.2 +++ lua/lualib.h 17 Aug 2008 18:31:34 -0000 1.3 @@ -39,7 +39,6 @@ #define LUA_LOADLIBNAME "package" LUALIB_API int (luaopen_package) (lua_State *L); - /* open all previous libraries */ LUALIB_API void (luaL_openlibs) (lua_State *L); @@ . patch -p0 <<'@@ .' Index: lua/shadow/chkname.h ============================================================================ $ cvs diff -u -r0 -r1.1 chkname.h --- /dev/null 2008-08-17 20:31:29 +0200 +++ chkname.h 2008-08-17 20:31:36 +0200 @@ -0,0 +1,21 @@ +/* + * This file was originally distributed as part of + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* $Id: chkname.h,v 1.1 2008/08/17 18:31:35 jbj Exp $ */ +#ifndef _CHKNAME_H_ +#define _CHKNAME_H_ + +/* + * check_user_name(), check_group_name() - check the new user/group + * name for validity; return value: 1 - OK, 0 - bad name + */ + +#include "defines.h" + +extern int check_user_name (const char *); +extern int check_group_name (const char *name); + +#endif @@ . patch -p0 <<'@@ .' Index: lua/shadow/commonio.c ============================================================================ $ cvs diff -u -r0 -r1.1 commonio.c --- /dev/null 2008-08-17 20:31:29 +0200 +++ commonio.c 2008-08-17 20:31:36 +0200 @@ -0,0 +1,945 @@ +/* + * This file was originally distributed as part of + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + + +#include "config.h" + +#ident "$Id: commonio.c,v 1.1 2008/08/17 18:31:35 jbj Exp $" + +#include "defines.h" +#include <sys/stat.h> +#include <stdlib.h> +#include <limits.h> +#include <utime.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <signal.h> +#include <pwd.h> +#include "nscd.h" +#ifdef HAVE_SHADOW_H +#include <shadow.h> +#endif +#ifdef WITH_SELINUX +#include <selinux/selinux.h> +static security_context_t old_context = NULL; +#endif +#include "commonio.h" + +/* local function prototypes */ +static int lrename (const char *, const char *); +static int check_link_count (const char *); +static int do_lock_file (const char *, const char *); +static FILE *fopen_set_perms (const char *, const char *, const struct stat *); +static int create_backup (const char *, FILE *); +static void free_linked_list (struct commonio_db *); +static void add_one_entry (struct commonio_db *, struct commonio_entry *); +static int name_is_nis (const char *); +static int write_all (const struct commonio_db *); +static struct commonio_entry *find_entry_by_name (struct commonio_db *, + const char *); + +static int lock_count = 0; +static int nscd_need_reload = 0; + +/* + * Simple rename(P) alternative that attempts to rename to symlink + * target. + */ +int lrename (const char *old, const char *new) +{ + + char resolved_path[PATH_MAX]; + int res; + +#if defined(S_ISLNK) + struct stat sb = { 0 }; + if (lstat (new, &sb) == 0 && S_ISLNK (sb.st_mode)) { + if (realpath (new, resolved_path) == NULL) { + perror ("realpath in lrename()"); + } else { + new = resolved_path; + } + } +#endif + res = rename (old, new); + return res; +} + +static int check_link_count (const char *file) +{ + struct stat sb; + + if (stat (file, &sb) != 0) + return 0; + + if (sb.st_nlink != 2) + return 0; + + return 1; +} + + +static int do_lock_file (const char *file, const char *lock) +{ + int fd; + int pid; + int len; + int retval; + char buf[32]; + + if ((fd = open (file, O_CREAT | O_EXCL | O_WRONLY, 0600)) == -1) + return 0; + + pid = getpid (); + snprintf (buf, sizeof buf, "%d", pid); + len = strlen (buf) + 1; + if (write (fd, buf, len) != len) { + close (fd); + unlink (file); + return 0; + } + close (fd); + + if (link (file, lock) == 0) { + retval = check_link_count (file); + unlink (file); + return retval; + } + + if ((fd = open (lock, O_RDWR)) == -1) { + unlink (file); + errno = EINVAL; + return 0; + } + len = read (fd, buf, sizeof (buf) - 1); + close (fd); + if (len <= 0) { + unlink (file); + errno = EINVAL; + return 0; + } + buf[len] = '\0'; + if ((pid = strtol (buf, (char **) 0, 10)) == 0) { + unlink (file); + errno = EINVAL; + return 0; + } + if (kill (pid, 0) == 0) { + unlink (file); + errno = EEXIST; + return 0; + } + if (unlink (lock) != 0) { + unlink (file); + return 0; + } + + retval = 0; + if (link (file, lock) == 0 && check_link_count (file)) + retval = 1; + + unlink (file); + return retval; +} + + +static FILE *fopen_set_perms (const char *name, const char *mode, + const struct stat *sb) +{ + FILE *fp; + mode_t mask; + + mask = umask (0777); + fp = fopen (name, mode); + umask (mask); + if (!fp) + return NULL; + +#ifdef HAVE_FCHOWN + if (fchown (fileno (fp), sb->st_uid, sb->st_gid)) + goto fail; +#else + if (chown (name, sb->st_mode)) + goto fail; +#endif + +#ifdef HAVE_FCHMOD + if (fchmod (fileno (fp), sb->st_mode & 0664)) + goto fail; +#else + if (chmod (name, sb->st_mode & 0664)) + goto fail; +#endif + return fp; + + fail: + fclose (fp); + unlink (name); + return NULL; +} + + +static int create_backup (const char *backup, FILE * fp) +{ + struct stat sb; + struct utimbuf ub; + FILE *bkfp; + int c; + mode_t mask; + + if (fstat (fileno (fp), &sb)) + return -1; + + mask = umask (077); + bkfp = fopen (backup, "w"); + umask (mask); + if (!bkfp) + return -1; + + /* TODO: faster copy, not one-char-at-a-time. --marekm */ + c = 0; + if (fseek (fp, 0, SEEK_SET) == 0) + while ((c = getc (fp)) != EOF) { + if (putc (c, bkfp) == EOF) + break; + } + if (c != EOF || ferror (fp) || fflush (bkfp)) { + fclose (bkfp); + return -1; + } + if (fclose (bkfp)) + return -1; + + ub.actime = sb.st_atime; + ub.modtime = sb.st_mtime; + utime (backup, &ub); + return 0; +} + + +static void free_linked_list (struct commonio_db *db) +{ + struct commonio_entry *p; + + while (db->head) { + p = db->head; + db->head = p->next; + + if (p->line) + free (p->line); + + if (p->eptr) + db->ops->free (p->eptr); + + free (p); + } + db->tail = NULL; +} + + +int commonio_setname (struct commonio_db *db, const char *name) +{ + snprintf (db->filename, sizeof (db->filename), "%s", name); + return 1; +} + + +int commonio_present (const struct commonio_db *db) +{ + return (access (db->filename, F_OK) == 0); +} + + +int commonio_lock_nowait (struct commonio_db *db) +{ + char file[1024]; + char lock[1024]; + + if (db->locked) + return 1; + + snprintf (file, sizeof file, "%s.%ld", db->filename, (long) getpid ()); + snprintf (lock, sizeof lock, "%s.lock", db->filename); + if (do_lock_file (file, lock)) { + db->locked = 1; + lock_count++; + return 1; + } + return 0; +} + + +int commonio_lock (struct commonio_db *db) +{ + + +#ifdef HAVE_LCKPWDF +#if 0 + printf("Locking file with LCKPWDF %s\n", db->filename); +#endif + /* + * only if the system libc has a real lckpwdf() - the one from + * lockpw.c calls us and would cause infinite recursion! + */ + + /* + * Call lckpwdf() on the first lock. + * If it succeeds, call *_lock() only once + * (no retries, it should always succeed). + */ + if (lock_count == 0) { + if (lckpwdf () == -1) + return 0; /* failure */ + } + + if (commonio_lock_nowait (db)) + return 1; /* success */ + + ulckpwdf (); + return 0; /* failure */ +#else + int i; + + printf("Locking file without LCKPWDF %s\n", db->filename); + + /* + * lckpwdf() not used - do it the old way. + */ +#ifndef LOCK_TRIES +#define LOCK_TRIES 15 +#endif + +#ifndef LOCK_SLEEP +#define LOCK_SLEEP 1 +#endif + for (i = 0; i < LOCK_TRIES; i++) { + if (i > 0) + sleep (LOCK_SLEEP); /* delay between retries */ + if (commonio_lock_nowait (db)) + return 1; /* success */ + /* no unnecessary retries on "permission denied" errors */ + if (geteuid () != 0) + return 0; + } + return 0; /* failure */ +#endif +} + +static void dec_lock_count (void) +{ + if (lock_count > 0) { + lock_count--; + if (lock_count == 0) { + /* Tell nscd when lock count goes to zero, + if any of the files were changed. */ + if (nscd_need_reload) { +#if 0 /* no cache flushin' */ + nscd_flush_cache ("passwd"); + nscd_flush_cache ("group"); +#endif + nscd_need_reload = 0; + } +#ifdef HAVE_LCKPWDF + ulckpwdf (); +#endif + } + } +} + + +int commonio_unlock (struct commonio_db *db) +{ + char lock[1024]; + + if (db->isopen) { + db->readonly = 1; + if (!commonio_close (db)) { + if (db->locked) + dec_lock_count (); + return 0; + } + } + if (db->locked) { + /* + * Unlock in reverse order: remove the lock file, + * then call ulckpwdf() (if used) on last unlock. + */ + db->locked = 0; + snprintf (lock, sizeof lock, "%s.lock", db->filename); + unlink (lock); + dec_lock_count (); + return 1; + } + return 0; +} + + +static void add_one_entry (struct commonio_db *db, struct commonio_entry *p) +{ + p->next = NULL; + p->prev = db->tail; + if (!db->head) + db->head = p; + if (db->tail) + db->tail->next = p; + db->tail = p; +} + + +static int name_is_nis (const char *n) +{ + return (n[0] == '+' || n[0] == '-'); +} + + +/* + * New entries are inserted before the first NIS entry. Order is preserved + * when db is written out. + */ +#ifndef KEEP_NIS_AT_END +#define KEEP_NIS_AT_END 1 +#endif + +#if KEEP_NIS_AT_END +static void add_one_entry_nis (struct commonio_db *, struct commonio_entry *); + +static void +add_one_entry_nis (struct commonio_db *db, struct commonio_entry *newp) +{ + struct commonio_entry *p; + + for (p = db->head; p; p = p->next) { + if (name_is_nis + (p->eptr ? db->ops->getname (p->eptr) : p->line)) { + newp->next = p; + newp->prev = p->prev; + if (p->prev) + p->prev->next = newp; + else + db->head = newp; + p->prev = newp; + return; + } + } + add_one_entry (db, newp); +} +#endif /* KEEP_NIS_AT_END */ + +/* Initial buffer size, as well as increment if not sufficient + (for reading very long lines in group files). */ +#define BUFLEN 4096 + +int commonio_open (struct commonio_db *db, int mode) +{ + char *buf; + char *cp; + char *line; + struct commonio_entry *p; + void *eptr; + int flags = mode; + int buflen; + int saved_errno; + + mode &= ~O_CREAT; + + if (db->isopen || (mode != O_RDONLY && mode != O_RDWR)) { + errno = EINVAL; + return 0; + } + db->readonly = (mode == O_RDONLY); + if (!db->readonly && !db->locked) { + errno = EACCES; + return 0; + } + + db->head = db->tail = db->cursor = NULL; + db->changed = 0; + + db->fp = fopen (db->filename, db->readonly ? "r" : "r+"); + + /* + * If O_CREAT was specified and the file didn't exist, it will be + * created by commonio_close(). We have no entries to read yet. --marekm + */ + if (!db->fp) { + if ((flags & O_CREAT) && errno == ENOENT) { + db->isopen = 1; + return 1; + } + return 0; + } + + /* not not inherit fd */ + fcntl(fileno(db->fp), F_SETFD, FD_CLOEXEC); + +#ifdef WITH_SELINUX + db->scontext = NULL; + if ((is_selinux_enabled () > 0) && (!db->readonly)) { + if (fgetfilecon (fileno (db->fp), &db->scontext) < 0) { + goto cleanup_errno; + } + } +#endif + + buflen = BUFLEN; + buf = (char *) malloc (buflen); + if (!buf) + goto cleanup_ENOMEM; + + while (db->ops->fgets (buf, buflen, db->fp)) { +#if 0 + printf("Reading from %s\n",db->filename); +#endif + while (!(cp = strrchr (buf, '\n')) && !feof (db->fp)) { + int len; + + buflen += BUFLEN; + cp = (char *) realloc (buf, buflen); + if (!cp) + goto cleanup_buf; + buf = cp; + len = strlen (buf); + db->ops->fgets (buf + len, buflen - len, db->fp); + } + if ((cp = strrchr (buf, '\n'))) + *cp = '\0'; + + if (!(line = strdup (buf))) + goto cleanup_buf; + + if (name_is_nis (line)) { + eptr = NULL; + } else if ((eptr = db->ops->parse (line))) { + eptr = db->ops->dup (eptr); + if (!eptr) + goto cleanup_line; + } + + p = (struct commonio_entry *) malloc (sizeof *p); + if (!p) + goto cleanup_entry; + + p->eptr = eptr; + p->line = line; + p->changed = 0; + + add_one_entry (db, p); + } + + free (buf); + + if (ferror (db->fp)) + goto cleanup_errno; + + db->isopen = 1; + return 1; + + cleanup_entry: + if (eptr) + db->ops->free (eptr); + cleanup_line: + free (line); + cleanup_buf: + free (buf); + cleanup_ENOMEM: + errno = ENOMEM; + cleanup_errno: + saved_errno = errno; + free_linked_list (db); +#ifdef WITH_SELINUX + if (db->scontext != NULL) { + freecon (db->scontext); + db->scontext = NULL; + } +#endif + fclose (db->fp); + db->fp = NULL; + errno = saved_errno; + return 0; +} + +/* + * Sort given db according to cmp function (usually compares uids) + */ +int +commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *)) +{ + struct commonio_entry **entries, *ptr; + int n = 0, i; + + for (ptr = db->head; ptr; ptr = ptr->next) + n++; + + if (n <= 1) + return 0; + + entries = malloc (n * sizeof (struct commonio_entry *)); + if (entries == NULL) + return -1; + + n = 0; + for (ptr = db->head; ptr; ptr = ptr->next) + entries[n++] = ptr; + qsort (entries, n, sizeof (struct commonio_entry *), cmp); + + db->head = entries[0]; + db->tail = entries[--n]; + db->head->prev = NULL; + db->head->next = entries[1]; + db->tail->prev = entries[n - 1]; + db->tail->next = NULL; + + for (i = 1; i < n; i++) { + entries[i]->prev = entries[i - 1]; + entries[i]->next = entries[i + 1]; + } + + free (entries); + db->changed = 1; + + return 0; +} + +/* + * Sort entries in db according to order in another. + */ +int commonio_sort_wrt (struct commonio_db *shadow, struct commonio_db *passwd) +{ + struct commonio_entry *head = NULL, *pw_ptr, *spw_ptr; + const char *name; + + if (!shadow || !shadow->head) + return 0; + + for (pw_ptr = passwd->head; pw_ptr; pw_ptr = pw_ptr->next) { + if (pw_ptr->eptr == NULL) + continue; + name = passwd->ops->getname (pw_ptr->eptr); + for (spw_ptr = shadow->head; spw_ptr; spw_ptr = spw_ptr->next) + if (strcmp (name, shadow->ops->getname (spw_ptr->eptr)) + == 0) + break; + if (spw_ptr == NULL) + continue; + commonio_del_entry (shadow, spw_ptr); + spw_ptr->next = head; + head = spw_ptr; + } + + for (spw_ptr = head; spw_ptr; spw_ptr = head) { + head = head->next; + + if (shadow->head) + shadow->head->prev = spw_ptr; + spw_ptr->next = shadow->head; + shadow->head = spw_ptr; + } + + shadow->head->prev = NULL; + shadow->changed = 1; + + return 0; +} + +static int write_all (const struct commonio_db *db) +{ + const struct commonio_entry *p; + void *eptr; + + for (p = db->head; p; p = p->next) { + if (p->changed) { + eptr = p->eptr; + if (db->ops->put (eptr, db->fp)) + return -1; + } else if (p->line) { + if (db->ops->fputs (p->line, db->fp) == EOF) + return -1; + if (putc ('\n', db->fp) == EOF) + return -1; + } + } + return 0; +} + + +int commonio_close (struct commonio_db *db) +{ + char buf[1024]; + int errors = 0; + struct stat sb; + + if (!db->isopen) { + errno = EINVAL; + return 0; + } + db->isopen = 0; + + if (!db->changed || db->readonly) { + fclose (db->fp); + db->fp = NULL; + goto success; + } + + memzero (&sb, sizeof sb); + if (db->fp) { + if (fstat (fileno (db->fp), &sb)) { + fclose (db->fp); + db->fp = NULL; + goto fail; + } +#ifdef WITH_SELINUX + if (db->scontext != NULL) { + int stat = getfscreatecon (&old_context); + + if (stat < 0) { + errors++; + goto fail; + } + if (setfscreatecon (db->scontext) < 0) { + errors++; + goto fail; + } + } +#endif + /* + * Create backup file. + */ + snprintf (buf, sizeof buf, "%s-", db->filename); + + if (create_backup (buf, db->fp)) + errors++; + + if (fclose (db->fp)) + errors++; + + if (errors) { + db->fp = NULL; + goto fail; + } + } else { + /* + * Default permissions for new [g]shadow files. + * (passwd and group always exist...) + */ + sb.st_mode = 0400; + sb.st_uid = 0; + sb.st_gid = 0; + } + + snprintf (buf, sizeof buf, "%s+", db->filename); + + db->fp = fopen_set_perms (buf, "w", &sb); + if (!db->fp) + goto fail; + + if (write_all (db)) + errors++; + + if (fflush (db->fp)) + errors++; +#ifdef HAVE_FSYNC + if (fsync (fileno (db->fp))) + errors++; +#else + sync (); +#endif + if (fclose (db->fp)) + errors++; + + db->fp = NULL; + + if (errors) { + unlink (buf); + goto fail; + } + + if (lrename (buf, db->filename)) + goto fail; + + nscd_need_reload = 1; + goto success; + fail: + errors++; + success: + +#ifdef WITH_SELINUX + if (db->scontext != NULL) { + if (setfscreatecon (old_context) < 0) { + errors++; + } + if (old_context != NULL) { + freecon (old_context); + old_context = NULL; + } + freecon (db->scontext); + db->scontext = NULL; + } +#endif + free_linked_list (db); + return errors == 0; +} + + +static struct commonio_entry *find_entry_by_name (struct commonio_db *db, + const char *name) +{ + struct commonio_entry *p; + void *ep; + + for (p = db->head; p; p = p->next) { + ep = p->eptr; + if (ep && strcmp (db->ops->getname (ep), name) == 0) + break; + } + return p; +} + + +int commonio_update (struct commonio_db *db, const void *eptr) +{ + struct commonio_entry *p; + void *nentry; + + if (!db->isopen || db->readonly) { + errno = EINVAL; + return 0; + } + if (!(nentry = db->ops->dup (eptr))) { + errno = ENOMEM; + return 0; + } + p = find_entry_by_name (db, db->ops->getname (eptr)); + if (p) { + db->ops->free (p->eptr); + p->eptr = nentry; + p->changed = 1; + db->cursor = p; + + db->changed = 1; + return 1; + } + /* not found, new entry */ + p = (struct commonio_entry *) malloc (sizeof *p); + if (!p) { + db->ops->free (nentry); + errno = ENOMEM; + return 0; + } + + p->eptr = nentry; + p->line = NULL; + p->changed = 1; + +#if KEEP_NIS_AT_END + add_one_entry_nis (db, p); +#else + add_one_entry (db, p); +#endif +#if 0 + printf("Entry added to db\n"); +#endif + db->changed = 1; + return 1; +} + + +void commonio_del_entry (struct commonio_db *db, const struct commonio_entry *p) +{ + if (p == db->cursor) + db->cursor = p->next; + + if (p->prev) + p->prev->next = p->next; + else + db->head = p->next; + + if (p->next) + p->next->prev = p->prev; + else + db->tail = p->prev; + + db->changed = 1; +} + + +int commonio_remove (struct commonio_db *db, const char *name) +{ + struct commonio_entry *p; + + if (!db->isopen || db->readonly) { + errno = EINVAL; + return 0; + } + p = find_entry_by_name (db, name); + if (!p) { + errno = ENOENT; + return 0; + } + + commonio_del_entry (db, p); + + if (p->line) + free (p->line); + + if (p->eptr) + db->ops->free (p->eptr); + + return 1; +} + + +const void *commonio_locate (struct commonio_db *db, const char *name) +{ + struct commonio_entry *p; + + if (!db->isopen) { + errno = EINVAL; + return NULL; + } + p = find_entry_by_name (db, name); + if (!p) { + errno = ENOENT; + return NULL; + } + db->cursor = p; + return p->eptr; +} + + +int commonio_rewind (struct commonio_db *db) +{ + if (!db->isopen) { + errno = EINVAL; + return 0; + } + db->cursor = NULL; + return 1; +} + + +const void *commonio_next (struct commonio_db *db) +{ + void *eptr; + + if (!db->isopen) { + errno = EINVAL; + return 0; + } + if (db->cursor == NULL) + db->cursor = db->head; + else + db->cursor = db->cursor->next; + + while (db->cursor) { + eptr = db->cursor->eptr; + if (eptr) + return eptr; + + db->cursor = db->cursor->next; + } + return NULL; +} @@ . patch -p0 <<'@@ .' Index: lua/shadow/commonio.h ============================================================================ $ cvs diff -u -r0 -r1.1 commonio.h --- /dev/null 2008-08-17 20:31:29 +0200 +++ commonio.h 2008-08-17 20:31:36 +0200 @@ -0,0 +1,116 @@ +/* + * This file was originally distributed as part of + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* $Id: commonio.h,v 1.1 2008/08/17 18:31:35 jbj Exp $ */ + +#ifdef WITH_SELINUX +#include <selinux/selinux.h> +#endif +/* + * Linked list entry. + */ +struct commonio_entry { + char *line; + void *eptr; /* struct passwd, struct spwd, ... */ + struct commonio_entry *prev, *next; + int changed:1; +}; + +/* + * Operations depending on database type: passwd, group, shadow etc. + */ +struct commonio_ops { + /* + * Make a copy of the object (for example, struct passwd) + * and all strings pointed by it, in malloced memory. + */ + void *(*dup) (const void *); + + /* + * free() the object including any strings pointed by it. + */ + void (*free) (void *); + + /* + * Return the name of the object (for example, pw_name + * for struct passwd). + */ + const char *(*getname) (const void *); + + /* + * Parse a string, return object (in static area - + * should be copied using the dup operation above). + */ + void *(*parse) (const char *); + + /* + * Write the object to the file (this calls putpwent() + * for struct passwd, for example). + */ + int (*put) (const void *, FILE *); + + /* + * fgets and fputs (can be replaced by versions that + * understand line continuation conventions). + */ + char *(*fgets) (char *, int, FILE *); + int (*fputs) (const char *, FILE *); +}; + +/* + * Database structure. + */ +struct commonio_db { + /* + * Name of the data file. + */ + char filename[1024]; + + /* + * Operations from above. + */ + struct commonio_ops *ops; + + /* + * Currently open file stream. + */ + FILE *fp; + +#ifdef WITH_SELINUX + security_context_t scontext; +#endif + /* + * Head, tail, current position in linked list. + */ + struct commonio_entry *head, *tail, *cursor; + + /* + * Various flags. + */ + int changed:1; + int isopen:1; + int locked:1; + int readonly:1; +}; + +extern int commonio_setname (struct commonio_db *, const char *); +extern int commonio_present (const struct commonio_db *); +extern int commonio_lock (struct commonio_db *); +extern int commonio_lock_nowait (struct commonio_db *); +extern int commonio_open (struct commonio_db *, int); +extern const void *commonio_locate (struct commonio_db *, const char *); +extern int commonio_update (struct commonio_db *, const void *); +extern int commonio_remove (struct commonio_db *, const char *); +extern int commonio_rewind (struct commonio_db *); +extern const void *commonio_next (struct commonio_db *); +extern int commonio_close (struct commonio_db *); +extern int commonio_unlock (struct commonio_db *); +extern void commonio_del_entry (struct commonio_db *, + const struct commonio_entry *); +extern int commonio_sort_wrt (struct commonio_db *shadow, + struct commonio_db *passwd); +extern int commonio_sort (struct commonio_db *db, + int (*cmp) (const void *, const void *)); @@ . patch -p0 <<'@@ .' Index: lua/shadow/config.h ============================================================================ $ cvs diff -u -r0 -r1.1 config.h --- /dev/null 2008-08-17 20:31:29 +0200 +++ config.h 2008-08-17 20:31:36 +0200 @@ -0,0 +1,412 @@ +/* + * This file was originally distributed as part of + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* config.h. Generated by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#define ENABLE_NLS 1 + +/* Path for faillog file. */ +#define FAILLOG_FILE "/var/log/faillog" + +/* Define to the type of elements in the array set by `getgroups'. Usually + this is either `int' or `gid_t'. */ +#define GETGROUPS_T gid_t + +/* Define to 1 if you have the `a64l' function. */ +#define HAVE_A64L 1 + +/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the + CoreFoundation framework. */ +/* #undef HAVE_CFLOCALECOPYCURRENT */ + +/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in + the CoreFoundation framework. */ +/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */ + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +#define HAVE_DCGETTEXT 1 + +/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `fchmod' function. */ +#define HAVE_FCHMOD 1 + +/* Define to 1 if you have the `fchown' function. */ +#define HAVE_FCHOWN 1 + +/* Define to 1 if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fsync' function. */ +#define HAVE_FSYNC 1 + +/* Define to 1 if you have the `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostname' function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define to 1 if you have the `getspnam' function. */ +#define HAVE_GETSPNAM 1 + +/* Define if the GNU gettext() function is already present or preinstalled. */ +#define HAVE_GETTEXT 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `getusershell' function. */ +#define HAVE_GETUSERSHELL 1 + +/* Define to 1 if you have the `getutent' function. */ +#define HAVE_GETUTENT 1 + +/* Define to 1 if you have the <gshadow.h> header file. */ +/* #undef HAVE_GSHADOW_H */ + +/* Define if you have the iconv() function. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the `initgroups' function. */ +#define HAVE_INITGROUPS 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the <lastlog.h> header file. */ +#define HAVE_LASTLOG_H 1 + +/* Define to 1 if you have the `lchown' function. */ +#define HAVE_LCHOWN 1 + +/* Define to 1 if you have the `lckpwdf' function. */ +#define HAVE_LCKPWDF 1 + +/* Defined if you have libcrack. */ +/* #undef HAVE_LIBCRACK */ + +/* Defined if you have the ts&szs cracklib. */ +/* #undef HAVE_LIBCRACK_HIST */ + +/* Defined if it includes *Pw functions. */ +/* #undef HAVE_LIBCRACK_PW */ + +/* Define to 1 if you have the <limits.h> header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if struct lastlog has ll_host */ +#define HAVE_LL_HOST 1 + +/* Define to 1 if you have the <locale.h> header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `mkdir' function. */ +#define HAVE_MKDIR 1 + +/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the <paths.h> header file. */ +#define HAVE_PATHS_H 1 + +/* Define to 1 if you have the `putgrent' function. */ +#define HAVE_PUTGRENT 1 + +/* Define to 1 if you have the `putpwent' function. */ +#define HAVE_PUTPWENT 1 + +/* Define to 1 if you have the `putspent' function. */ +#define HAVE_PUTSPENT 1 + +/* Define to 1 if you have the `rename' function. */ +#define HAVE_RENAME 1 + +/* Define to 1 if you have the `rmdir' function. */ +#define HAVE_RMDIR 1 + +/* Define to 1 if you have the <rpc/key_prot.h> header file. */ +#define HAVE_RPC_KEY_PROT_H 1 + +/* Define to 1 if you have the <selinux/selinux.h> header file. */ +/* #undef HAVE_SELINUX_SELINUX_H */ + +/* Define to 1 if you have the `setgroups' function. */ +#define HAVE_SETGROUPS 1 + +/* Define to 1 if you have the `sgetgrent' function. */ +/* #undef HAVE_SGETGRENT */ + +/* Define to 1 if you have the `sgetpwent' function. */ +/* #undef HAVE_SGETPWENT */ + +/* Define to 1 if you have the `sgetspent' function. */ +#define HAVE_SGETSPENT 1 + +/* Define to 1 if you have the <sgtty.h> header file. */ +#define HAVE_SGTTY_H 1 + +/* Have working shadow group support in libc */ +/* #undef HAVE_SHADOWGRP */ + +/* Define to 1 if you have the <shadow.h> header file. */ +#define HAVE_SHADOW_H 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strstr' function. */ +#define HAVE_STRSTR 1 + +/* Define to 1 if `st_rdev' is member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_RDEV 1 + +/* Define to 1 if you have the <syslog.h> header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the <sys/ioctl.h> header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the <sys/resource.h> header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/time.h> header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the <termios.h> header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define to 1 if you have the <termio.h> header file. */ +#define HAVE_TERMIO_H 1 + +/* Define to 1 if you have the <ulimit.h> header file. */ +#define HAVE_ULIMIT_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `updwtmp' function. */ +#define HAVE_UPDWTMP 1 + +/* Define to 1 if you have the `updwtmpx' function. */ +#define HAVE_UPDWTMPX 1 + +/* Define to 1 if you have the <utime.h> header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */ +#define HAVE_UTIME_NULL 1 + +/* Define to 1 if you have the <utmpx.h> header file. */ +#define HAVE_UTMPX_H 1 + +/* Define to 1 if you have the <utmp.h> header file. */ +#define HAVE_UTMP_H 1 + +/* Path for lastlog file. */ +#define LASTLOG_FILE "/var/log/lastlog" + +/* Location of system mail spool directory. */ +#define MAIL_SPOOL_DIR "/var/mail" + +/* Name of user's mail spool file if stored in user's home directory. */ +/* #undef MAIL_SPOOL_FILE */ + +#if 0 +/* Name of package */ +#define PACKAGE "shadow" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" +#endif + +/* Path to passwd program. */ +#define PASSWD_PROGRAM "/usr/bin/passwd" + +/* Define to 1 if the C compiler supports function prototypes. */ +#define PROTOTYPES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define if login should support the -r flag for rlogind. */ +#define RLOGIN 1 + +/* Define to the ruserok() "success" return value (0 or 1). */ +#define RUSEROK 0 + +/* Define to 1 if the `setpgrp' function takes no argument. */ +#define SETPGRP_VOID 1 + +/* Define to support the shadow group file. */ +#define SHADOWGRP 1 + +/* Define to support S/Key logins. */ +/* #undef SKEY */ + +/* Define to support newer BSD S/Key API */ +/* #undef SKEY_BSD_STYLE */ + +/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to support /etc/suauth su access control. */ +#define SU_ACCESS 1 + +/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your <sys/time.h> declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Define to support Pluggable Authentication Modules */ +/* #undef USE_PAM */ + +/* Define to use syslog(). */ +#define USE_SYSLOG 1 + +/* Define if you have ut_host in struct utmp. */ +#define UT_HOST 1 + +#if 0 +/* Version number of package */ +#define VERSION "4.0.17" +#endif + +/* Define if you want to enable Audit messages */ +/* #undef WITH_AUDIT */ + +/* Build shadow with SELinux support */ +/* #undef WITH_SELINUX */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Path for utmp file. */ +#define _UTMP_FILE "/var/run/utmp" + +/* Path for wtmp file. */ +#define _WTMP_FILE "/var/log/wtmp" + +/* Define like PROTOTYPES; this can be used by system headers. */ +#define __PROTOTYPES 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to libshadow_getpass to use our own version of getpass(). */ +/* #undef getpass */ + +/* Define to `int' if <sys/types.h> doesn't define. */ +/* #undef gid_t */ + +/* Define to `int' if <sys/types.h> does not define. */ +/* #undef mode_t */ + +/* Define to `long' if <sys/types.h> does not define. */ +/* #undef off_t */ + +/* Define to `int' if <sys/types.h> does not define. */ +/* #undef pid_t */ + +/* Define to `int' if <sys/types.h> doesn't define. */ +/* #undef uid_t */ + +/* Define to ut_name if struct utmp has ut_name (not ut_user). */ +/* #undef ut_user */ @@ . patch -p0 <<'@@ .' Index: lua/shadow/copydir.c ============================================================================ $ cvs diff -u -r0 -r1.1 copydir.c --- /dev/null 2008-08-17 20:31:29 +0200 +++ copydir.c 2008-08-17 20:31:36 +0200 @@ -0,0 +1,452 @@ +/* + * This file was originally distributed as part of + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* + * Copyright 1991 - 1994, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#ident "$Id: copydir.c,v 1.1 2008/08/17 18:31:35 jbj Exp $" + +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdio.h> +#include "prototypes.h" +#include "defines.h" +#ifdef WITH_SELINUX +#include <selinux/selinux.h> +static int selinux_enabled = -1; +#endif +static const char *src_orig; +static const char *dst_orig; + +struct link_name { + dev_t ln_dev; + ino_t ln_ino; + int ln_count; + char *ln_name; + struct link_name *ln_next; +}; +static struct link_name *links; + +#ifdef WITH_SELINUX +static int selinux_file_context (const char *dst_name) +{ + security_context_t scontext = NULL; + + if (selinux_enabled < 0) + selinux_enabled = is_selinux_enabled () > 0; + if (selinux_enabled) { + if (matchpathcon (dst_name, 0, &scontext) < 0) + if (security_getenforce ()) + return 1; + if (setfscreatecon (scontext) < 0) + if (security_getenforce ()) + return 1; + freecon (scontext); + } + return 0; +} +#endif + +/* + * remove_link - delete a link from the link list + */ + +static void remove_link (struct link_name *ln) +{ + struct link_name *lp; + + if (links == ln) { + links = ln->ln_next; + free (ln->ln_name); + free (ln); + return; + } + for (lp = links; lp; lp = lp->ln_next) + if (lp->ln_next == ln) + break; + + if (!lp) + return; + + lp->ln_next = lp->ln_next->ln_next; + free (ln->ln_name); + free (ln); +} + +/* + * check_link - see if a file is really a link + */ + +static struct link_name *check_link (const char *name, const struct stat *sb) +{ + struct link_name *lp; + int src_len; + int dst_len; + int name_len; + int len; + + for (lp = links; lp; lp = lp->ln_next) + if (lp->ln_dev == sb->st_dev && lp->ln_ino == sb->st_ino) + return lp; + + if (sb->st_nlink == 1) + return 0; + + lp = (struct link_name *) xmalloc (sizeof *lp); + src_len = strlen (src_orig); + dst_len = strlen (dst_orig); + name_len = strlen (name); + lp->ln_dev = sb->st_dev; + lp->ln_ino = sb->st_ino; + lp->ln_count = sb->st_nlink; + len = name_len - src_len + dst_len + 1; + lp->ln_name = xmalloc (len); + snprintf (lp->ln_name, len, "%s%s", dst_orig, name + src_len); + lp->ln_next = links; + links = lp; + + return 0; +} + +/* + * copy_tree - copy files in a directory tree + * + * copy_tree() walks a directory tree and copies ordinary files + * as it goes. + */ + +int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid) +{ + char src_name[1024]; + char dst_name[1024]; + char buf[1024]; + int ifd; + int ofd; + int err = 0; + int cnt; + int set_orig = 0; + struct DIRECT *ent; + struct stat sb; + struct link_name *lp; + DIR *dir; + + /* + * Make certain both directories exist. This routine is called + * after the home directory is created, or recursively after the + * target is created. It assumes the target directory exists. + */ + + if (access (src_root, F_OK) != 0 || access (dst_root, F_OK) != 0) + return -1; + + /* + * Open the source directory and read each entry. Every file + * entry in the directory is copied with the UID and GID set + * to the provided values. As an added security feature only + * regular files (and directories ...) are copied, and no file + * is made set-ID. + */ + + if (!(dir = opendir (src_root))) + return -1; + + if (src_orig == 0) { + src_orig = src_root; + dst_orig = dst_root; + set_orig++; + } + while ((ent = readdir (dir))) { + + /* + * Skip the "." and ".." entries + */ + + if (strcmp (ent->d_name, ".") == 0 || + strcmp (ent->d_name, "..") == 0) + continue; + + /* + * Make the filename for both the source and the + * destination files. + */ + + if (strlen (src_root) + strlen (ent->d_name) + 2 > + sizeof src_name) { + err++; + break; + } + snprintf (src_name, sizeof src_name, "%s/%s", src_root, + ent->d_name); + + if (strlen (dst_root) + strlen (ent->d_name) + 2 > + sizeof dst_name) { + err++; + break; + } + snprintf (dst_name, sizeof dst_name, "%s/%s", dst_root, + ent->d_name); + + if (LSTAT (src_name, &sb) == -1) + continue; + + if (S_ISDIR (sb.st_mode)) { + + /* + * Create a new target directory, make it owned by + * the user and then recursively copy that directory. + */ + +#ifdef WITH_SELINUX + selinux_file_context (dst_name); +#endif + if (mkdir (dst_name, sb.st_mode) + || chown (dst_name, + uid == (uid_t) - 1 ? sb.st_uid : uid, + gid == (gid_t) - 1 ? sb.st_gid : gid) + || chmod (dst_name, sb.st_mode) + || copy_tree (src_name, dst_name, uid, gid)) { + err++; + break; + } + continue; + } +#ifdef S_IFLNK + /* + * Copy any symbolic links + */ + + if (S_ISLNK (sb.st_mode)) { + char oldlink[1024]; + char dummy[1024]; + int len; + + /* + * Get the name of the file which the link points + * to. If that name begins with the original + * source directory name, that part of the link + * name will be replaced with the original + * destinateion directory name. + */ + + if ((len = + readlink (src_name, oldlink, + sizeof (oldlink) - 1)) < 0) { + err++; + break; + } + oldlink[len] = '\0'; /* readlink() does not NUL-terminate */ + if (!strncmp (oldlink, src_orig, strlen (src_orig))) { + snprintf (dummy, sizeof dummy, "%s%s", + dst_orig, + oldlink + strlen (src_orig)); + strcpy (oldlink, dummy); + } +#ifdef WITH_SELINUX + selinux_file_context (dst_name); +#endif + if (symlink (oldlink, dst_name) || + lchown (dst_name, + uid == (uid_t) - 1 ? sb.st_uid : uid, + gid == (gid_t) - 1 ? sb.st_gid : gid)) { + err++; + break; + } + continue; + } +#endif + + /* + * See if this is a previously copied link + */ + + if ((lp = check_link (src_name, &sb))) { + if (link (lp->ln_name, dst_name)) { + err++; + break; + } + if (unlink (src_name)) { + err++; + break; + } + if (--lp->ln_count <= 0) + remove_link (lp); + + continue; + } + + /* + * Deal with FIFOs and special files. The user really + * shouldn't have any of these, but it seems like it + * would be nice to copy everything ... + */ + + if (!S_ISREG (sb.st_mode)) { +#ifdef WITH_SELINUX + selinux_file_context (dst_name); +#endif + if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) + || chown (dst_name, + uid == (uid_t) - 1 ? sb.st_uid : uid, + gid == (gid_t) - 1 ? sb.st_gid : gid) + || chmod (dst_name, sb.st_mode & 07777)) { + err++; + break; + } + continue; + } + + /* + * Create the new file and copy the contents. The new + * file will be owned by the provided UID and GID values. + */ + + if ((ifd = open (src_name, O_RDONLY)) < 0) { + err++; + break; + } +#ifdef WITH_SELINUX + selinux_file_context (dst_name); +#endif + if ((ofd = + open (dst_name, O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0 + || chown (dst_name, + uid == (uid_t) - 1 ? sb.st_uid : uid, + gid == (gid_t) - 1 ? sb.st_gid : gid) + || chmod (dst_name, sb.st_mode & 07777)) { + close (ifd); + err++; + break; + } + while ((cnt = read (ifd, buf, sizeof buf)) > 0) { + if (write (ofd, buf, cnt) != cnt) { + cnt = -1; + break; + } + } + close (ifd); + close (ofd); + + if (cnt == -1) { + err++; + break; + } + } + closedir (dir); + + if (set_orig) { + src_orig = 0; + dst_orig = 0; + } + return err ? -1 : 0; +} + +/* + * remove_tree - remove files in a directory tree + * + * remove_tree() walks a directory tree and deletes all the files + * and directories. + */ + +int remove_tree (const char *root) +{ + char new_name[1024]; + int err = 0; + struct DIRECT *ent; + struct stat sb; + DIR *dir; + + /* + * Make certain the directory exists. + */ + + if (access (root, F_OK) != 0) + return -1; + + /* + * Open the source directory and read each entry. Every file + * entry in the directory is copied with the UID and GID set + * to the provided values. As an added security feature only + * regular files (and directories ...) are copied, and no file + * is made set-ID. + */ + + if (!(dir = opendir (root))) + return -1; + + while ((ent = readdir (dir))) { + + /* + * Skip the "." and ".." entries + */ + + if (strcmp (ent->d_name, ".") == 0 || + strcmp (ent->d_name, "..") == 0) + continue; + + /* + * Make the filename for the current entry. + */ + + if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) { + err++; + break; + } + snprintf (new_name, sizeof new_name, "%s/%s", root, + ent->d_name); + if (LSTAT (new_name, &sb) == -1) + continue; + + if (S_ISDIR (sb.st_mode)) { + + /* + * Recursively delete this directory. + */ + + if (remove_tree (new_name)) { + err++; + break; + } + if (rmdir (new_name)) { + err++; + break; + } + continue; + } + unlink (new_name); + } + closedir (dir); + + return err ? -1 : 0; +} @@ . patch -p0 <<'@@ .' Index: lua/shadow/defines.h ============================================================================ $ cvs diff -u -r0 -r1.1 defines.h --- /dev/null 2008-08-17 20:31:29 +0200 +++ defines.h 2008-08-17 20:31:36 +0200 @@ -0,0 +1,351 @@ +/* + * This file was originally distributed as part of + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* $Id: defines.h,v 1.1 2008/08/17 18:31:35 jbj Exp $ */ +/* some useful defines */ + +#ifndef _DEFINES_H_ +#define _DEFINES_H_ + +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) + +/* Take care of NLS matters. */ + +#if HAVE_LOCALE_H +# include <locale.h> +#endif + +#define gettext_noop(String) (String) +/* #define gettext_def(String) "#define String" */ + +#if ENABLE_NLS +# include <libintl.h> +# define _(Text) gettext (Text) +#else +# undef bindtextdomain +# define bindtextdomain(Domain, Directory) /* empty */ +# undef textdomain +# define textdomain(Domain) /* empty */ +# define _(Text) Text +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +#endif + +#if STDC_HEADERS +# include <stdlib.h> +# include <string.h> +#else /* not STDC_HEADERS */ +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif +char *strchr (), *strrchr (), *strtok (); + +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy((s), (d), (n)) +# endif +#endif /* not STDC_HEADERS */ + +#if HAVE_ERRNO_H +# include <errno.h> +#endif + +#include <sys/stat.h> +#include <sys/types.h> +#if HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else /* not TIME_WITH_SYS_TIME */ +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif /* not TIME_WITH_SYS_TIME */ + +#ifdef HAVE_MEMSET +# define memzero(ptr, size) memset((void *)(ptr), 0, (size)) +#else +# define memzero(ptr, size) bzero((char *)(ptr), (size)) +#endif +#define strzero(s) memzero(s, strlen(s)) /* warning: evaluates twice */ + +#ifdef HAVE_DIRENT_H /* DIR_SYSV */ +# include <dirent.h> +# define DIRECT dirent +#else +# ifdef HAVE_SYS_NDIR_H /* DIR_XENIX */ +# include <sys/ndir.h> +# endif +# ifdef HAVE_SYS_DIR_H /* DIR_??? */ +# include <sys/dir.h> +# endif +# ifdef HAVE_NDIR_H /* DIR_BSD */ +# include <ndir.h> +# endif +# define DIRECT direct +#endif + +/* + * Possible cases: + * - /usr/include/shadow.h exists and includes the shadow group stuff. + * - /usr/include/shadow.h exists, but we use our own gshadow.h. + * - /usr/include/shadow.h doesn't exist, use our own shadow.h and gshadow.h. + */ +#if HAVE_SHADOW_H +#include <shadow.h> +#if defined(SHADOWGRP) && !defined(GSHADOW) +#include "gshadow_.h" +#endif +#else /* not HAVE_SHADOW_H */ +#include "shadow_.h" +#ifdef SHADOWGRP +#include "gshadow_.h" +#endif +#endif /* not HAVE_SHADOW_H */ + +#include <limits.h> + +#ifndef NGROUPS_MAX +#ifdef NGROUPS +#define NGROUPS_MAX NGROUPS +#else +#define NGROUPS_MAX 64 +#endif +#endif + +#ifdef USE_SYSLOG +#include <syslog.h> + +#ifndef LOG_WARN +#define LOG_WARN LOG_WARNING +#endif + +/* LOG_NOWAIT is deprecated */ +#ifndef LOG_NOWAIT +#define LOG_NOWAIT 0 +#endif + +/* LOG_AUTH is deprecated, use LOG_AUTHPRIV instead */ +#ifndef LOG_AUTHPRIV +#define LOG_AUTHPRIV LOG_AUTH +#endif + +/* cleaner than lots of #ifdefs everywhere - use this as follows: + SYSLOG((LOG_CRIT, "user %s cracked root", user)); */ +#if ENABLE_NLS +/* Temporarily set LC_TIME to "C" to avoid strange dates in syslog. + This is a workaround for a more general syslog(d) design problem - + syslogd should log the current system time for each event, and not + trust the formatted time received from the unix domain (or worse, + UDP) socket. -MM */ +#define SYSLOG(x) \ + do { \ + char *saved_locale = setlocale(LC_ALL, NULL); \ + if (saved_locale) \ + saved_locale = strdup(saved_locale); \ + if (saved_locale) \ + setlocale(LC_TIME, "C"); \ + syslog x ; \ + if (saved_locale) { \ + setlocale(LC_ALL, saved_locale); \ + free(saved_locale); \ + } \ + } while (0) +#else /* !ENABLE_NLS */ +#define SYSLOG(x) syslog x +#endif /* !ENABLE_NLS */ + +#else /* !USE_SYSLOG */ + +#define SYSLOG(x) /* empty */ +#define openlog(a,b,c) /* empty */ +#define closelog() /* empty */ + +#endif /* !USE_SYSLOG */ + +/* The default syslog settings can now be changed here, + in just one place. */ + +#ifndef SYSLOG_OPTIONS +/* #define SYSLOG_OPTIONS (LOG_PID | LOG_CONS | LOG_NOWAIT) */ +#define SYSLOG_OPTIONS (LOG_PID) +#endif + +#ifndef SYSLOG_FACILITY +#define SYSLOG_FACILITY LOG_AUTHPRIV +#endif + +#define OPENLOG(progname) openlog(progname, SYSLOG_OPTIONS, SYSLOG_FACILITY) + +#ifndef F_OK +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif + +#ifdef STAT_MACROS_BROKEN +# define S_ISDIR(x) ((x) & S_IFMT) == S_IFDIR) +# define S_ISREG(x) ((x) & S_IFMT) == S_IFREG) +# ifdef S_IFLNK +# define S_ISLNK(x) ((x) & S_IFMT) == S_IFLNK) +# endif +#endif + +#ifndef S_ISLNK +#define S_ISLNK(x) (0) +#endif + +#if HAVE_LCHOWN +#define LCHOWN lchown +#else +#define LCHOWN chown +#endif + +#if HAVE_LSTAT +#define LSTAT lstat +#else +#define LSTAT stat +#endif + +#if HAVE_TERMIOS_H +# include <termios.h> +# define STTY(fd, termio) tcsetattr(fd, TCSANOW, termio) +# define GTTY(fd, termio) tcgetattr(fd, termio) +# define TERMIO struct termios +# define USE_TERMIOS +#else /* assumed HAVE_TERMIO_H */ +# include <sys/ioctl.h> +# include <termio.h> +# define STTY(fd, termio) ioctl(fd, TCSETA, termio) +# define GTTY(fd, termio) ioctl(fd, TCGETA, termio) +# define TEMRIO struct termio +# define USE_TERMIO +#endif + +/* + * Password aging constants + * + * DAY - seconds / day + * WEEK - seconds / week + * SCALE - seconds / aging unit + */ + +/* Solaris defines this in shadow.h */ +#ifndef DAY +#define DAY (24L*3600L) +#endif + +#define WEEK (7*DAY) + +#ifdef ITI_AGING +#define SCALE 1 +#else +#define SCALE DAY +#endif + +/* Copy string pointed by B to array A with size checking. It was originally + in lmain.c but is _very_ useful elsewhere. Some setuid root programs with + very sloppy coding used to assume that BUFSIZ will always be enough... */ + + /* danger - side effects */ +#define STRFCPY(A,B) \ + (strncpy((A), (B), sizeof(A) - 1), (A)[sizeof(A) - 1] = '\0') + +/* get rid of a few ugly repeated #ifdefs in pwent.c and grent.c */ +/* XXX - this is ugly too, configure should test it and not check for + any hardcoded system names, if possible. --marekm */ +#if defined(AIX) || defined(__linux__) +#define SETXXENT_TYPE void +#define SETXXENT_RET(x) return +#define SETXXENT_TEST(x) x; if (0) /* compiler should optimize this away */ +#else +#define SETXXENT_TYPE int +#define SETXXENT_RET(x) return(x) +#define SETXXENT_TEST(x) if (x) +#endif + +#ifndef PASSWD_FILE +#define PASSWD_FILE "/etc/passwd" +#endif + +#ifndef GROUP_FILE +#define GROUP_FILE "/etc/group" +#endif + +#ifndef SHADOW_FILE +#define SHADOW_FILE "/etc/shadow" +#endif + +#ifdef SHADOWGRP +#ifndef SGROUP_FILE +#define SGROUP_FILE "/etc/gshadow" +#endif +#endif + +#define PASSWD_PAG_FILE PASSWD_FILE ".pag" +#define GROUP_PAG_FILE GROUP_FILE ".pag" +#define SHADOW_PAG_FILE SHADOW_FILE ".pag" +#define SGROUP_PAG_FILE SGROUP_FILE ".pag" + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#ifdef sun /* hacks for compiling on SunOS */ +# ifndef SOLARIS +extern int fputs (); +extern char *strdup (); +extern char *strerror (); +# endif +#endif + +#ifndef HAVE_SNPRINTF +#include "snprintf.h" +#endif + +/* + * string to use for the pw_passwd field in /etc/passwd when using + * shadow passwords - most systems use "x" but there are a few + * exceptions, so it can be changed here if necessary. --marekm + */ +#ifndef SHADOW_PASSWD_STRING +#define SHADOW_PASSWD_STRING "x" +#endif + +#ifdef WITH_AUDIT +#ifdef __u8 /* in case we use pam < 0.80 */ +#undef __u8 +#endif +#ifdef __u32 +#undef __u32 +#endif + +#include <libaudit.h> +#endif + +#endif /* _DEFINES_H_ */ @@ . patch -p0 <<'@@ .' Index: lua/shadow/faillog.h ============================================================================ $ cvs diff -u -r0 -r1.1 faillog.h --- /dev/null 2008-08-17 20:31:29 +0200 +++ faillog.h 2008-08-17 20:31:36 +0200 @@ -0,0 +1,61 @@ +/* + * This file was originally distributed as part of + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* + * Copyright 1989 - 1994, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * faillog.h - login failure logging file format + * + * $Id: faillog.h,v 1.1 2008/08/17 18:31:35 jbj Exp $ + * + * The login failure file is maintained by login(1) and faillog(8) + * Each record in the file represents a separate UID and the file + * is indexed in that fashion. + */ + +#ifndef _FAILLOG_H +#define _FAILLOG_H + +struct faillog { + short fail_cnt; /* failures since last success */ + short fail_max; /* failures before turning account off */ + char fail_line[12]; /* last failure occured here */ + time_t fail_time; /* last failure occured then */ + /* + * If nonzero, the account will be re-enabled if there are no + * failures for fail_locktime seconds since last failure. + */ + long fail_locktime; +}; + +#endif @@ . patch -p0 <<'@@ .' Index: lua/shadow/fputsx.c ============================================================================ $ cvs diff -u -r0 -r1.1 fputsx.c --- /dev/null 2008-08-17 20:31:29 +0200 +++ fputsx.c 2008-08-17 20:31:36 +0200 @@ -0,0 +1,84 @@ +/* + * This file was originally distributed as part of + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified + * in WRLinux for inclusion in rpm. + */ + +/* + * Copyright 1990 - 1994, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include <stdio.h> +#include "defines.h" + +#ident "$Id: fputsx.c,v 1.1 2008/08/17 18:31:35 jbj Exp $" + + +char *fgetsx (char *buf, int cnt, FILE * f) +{ + char *cp = buf; + char *ep; + + while (cnt > 0) { + if (fgets (cp, cnt, f) == 0) { + if (cp == buf) + return 0; + else + break; + } + if ((ep =