int get_slot_number(int so) { char buf[8]; int rv; int nslot; if ((rv = write(so, "S", 1)) < 1) { warn("write"); goto err; } else if (rv != 1) { warnc(0, "write: fail."); goto err; } if ((rv = read(so, buf, sizeof buf)) < 0) { warn("read"); goto err; } buf[sizeof buf - 1] = 0; if (sscanf(buf, "%d", &nslot) != 1) { warnc(0, "Invalid response."); goto err; } return nslot; err: return -1; }
int get_slot_info(int so, int slot, char **manuf, char **version, char **device, int *state) { int rc = -1; int rv; static char buf[1024]; int slen; char *s; char *sl; char *_manuf; char *_version; char *_device; slen = snprintf(buf, sizeof buf, "N%d", slot); if ((rv = write(so, buf, slen)) < 0) { warn("write"); goto err; } else if (rv != slen) { warnc(0, "write"); goto err; } if ((rv = read(so, buf, sizeof buf)) < 0) { warn("read"); goto err; } s = buf; if ((sl = strsep(&s, "~")) == NULL) goto parse_err; if (atoi(sl) != slot) goto parse_err; if ((_manuf = strsep(&s, "~")) == NULL) goto parse_err; if ((_version = strsep(&s, "~")) == NULL) goto parse_err; if ((_device = strsep(&s, "~")) == NULL) goto parse_err; if (sscanf(s, "%1d", state) != 1) goto parse_err; if (s != NULL && strchr(s, '~') != NULL) goto parse_err; *manuf = strdup(_manuf); *version = strdup(_version); *device = strdup(_device); if (*manuf == NULL || *version == NULL || *device == NULL) { warn("strdup"); goto err; } rc = 0; err: return rc; parse_err: warnc(0, "Invalid response: %*s", rv, buf); return rc; }
static int read_kld(char *filename, char *kldname) { struct mod_metadata md; struct elf_file ef; void **p, **orgp; int error, eftype, nmlen; long start, finish, entries; char kldmodname[MAXMODNAME + 1], cval[MAXMODNAME + 1], *cp; if (verbose || dflag) printf("%s\n", filename); error = ef_open(filename, &ef, verbose); if (error) { error = ef_obj_open(filename, &ef, verbose); if (error) { if (verbose) warnc(error, "elf_open(%s)", filename); return error; } } eftype = EF_GET_TYPE(&ef); if (eftype != EFT_KLD && eftype != EFT_KERNEL) { EF_CLOSE(&ef); return 0; } if (!dflag) { cp = strrchr(kldname, '.'); nmlen = (cp != NULL) ? cp - kldname : (int)strlen(kldname); if (nmlen > MAXMODNAME) nmlen = MAXMODNAME; strlcpy(kldmodname, kldname, nmlen); /* fprintf(fxref, "%s:%s:%d\n", kldmodname, kldname, 0);*/ } do { check(EF_LOOKUP_SET(&ef, MDT_SETNAME, &start, &finish, &entries)); check(EF_SEG_READ_ENTRY_REL(&ef, start, sizeof(*p) * entries, (void *)&p)); orgp = p; while(entries--) { check(EF_SEG_READ_REL(&ef, (Elf_Off)*p, sizeof(md), &md)); p++; check(EF_SEG_READ(&ef, (Elf_Off)md.md_cval, sizeof(cval), cval)); cval[MAXMODNAME] = '\0'; parse_entry(&md, cval, &ef, kldname); } if (error) warnc(error, "error while reading %s", filename); free(orgp); } while(0); EF_CLOSE(&ef); return error; }
int main(int argc, char *argv[]) { char *progname; char *ttyname; int fd; int dofree; dofree = 0; progname = basename(argv[0]); if (argc != 2) errx(EX_USAGE, "usage: %s <ttyname>\n", progname); if (geteuid() != 0) errx(EX_NOPERM, "Sorry\n"); if (argv[1][0] == '/') { ttyname = argv[1]; } else { size_t len, maxpath, result; len = strlen(argv[1]) + sizeof(DEVPATHNAME) + 1; maxpath = pathconf(DEVPATHNAME, _PC_PATH_MAX); if (len > maxpath) { warnc(ENAMETOOLONG, ttyname); exit(EX_DATAERR); } ttyname = malloc(len); if (ttyname == NULL) { warnc(ENOMEM, "malloc"); exit(EX_OSERR); } dofree = 1; result = snprintf(ttyname, len, "%s/%s", DEVPATHNAME, argv[1]); if (result >= len) warnc(ENOMEM, "snprintf"); } fd = open(ttyname, O_RDWR); if (fd == -1) { warnc(errno, "open %s", ttyname); if (dofree) free(ttyname); exit(EX_OSERR); } if (0 != ioctl(fd, TIOCNXCL, 0)) warnc(errno, "ioctl TIOCNXCL %s", ttyname); if (dofree) free(ttyname); exit(0); }
/* Helper function to set a drive to a given state. */ static int drive_set_state(char *drive, U8 Action, U8 State, const char *name) { CONFIG_PAGE_RAID_PHYS_DISK_0 *info; struct mpt_drive_list *list; U8 PhysDiskNum; int error, fd; fd = mpt_open(mpt_unit); if (fd < 0) { error = errno; warn("mpt_open"); return (error); } list = mpt_pd_list(fd); if (list == NULL) { close(fd); return (errno); } if (mpt_lookup_drive(list, drive, &PhysDiskNum) < 0) { error = errno; warn("Failed to find drive %s", drive); close(fd); return (error); } mpt_free_pd_list(list); /* Get the info for this drive. */ info = mpt_pd_info(fd, PhysDiskNum, NULL); if (info == NULL) { error = errno; warn("Failed to fetch info for drive %u", PhysDiskNum); close(fd); return (error); } /* Try to change the state. */ if (info->PhysDiskStatus.State == State) { warnx("Drive %u is already in the desired state", PhysDiskNum); free(info); close(fd); return (EINVAL); } error = mpt_raid_action(fd, Action, 0, 0, PhysDiskNum, 0, NULL, 0, NULL, NULL, 0, NULL, NULL, 0); if (error) { warnc(error, "Failed to set drive %u to %s", PhysDiskNum, name); free(info); close(fd); return (error); } free(info); close(fd); return (0); }
/* * set_profile reads $HOME/.indent.pro and ./.indent.pro and handles arguments * given in these files. */ void set_profile(void) { FILE *f; char fname[BUFSIZ]; char *home; static char prof[] = ".indent.pro"; home = getenv("HOME"); if (home != NULL && *home != '\0') { if (snprintf(fname, sizeof fname, "%s/%s", home, prof) >= sizeof fname) { warnc(ENAMETOOLONG, "%s/%s", home, prof); return; } if ((f = fopen(option_source = fname, "r")) != NULL) { scan_profile(f); (void) fclose(f); } } if ((f = fopen(option_source = prof, "r")) != NULL) { scan_profile(f); (void) fclose(f); } option_source = "Command line"; }
/* * Parse -S option. */ static unsigned long long parse_memory_buffer_value(const char *value) { if (value == NULL) return (available_free_memory); else { char *endptr; unsigned long long membuf; endptr = NULL; errno = 0; membuf = strtoll(value, &endptr, 10); if (errno != 0) { warn("%s",getstr(4)); membuf = available_free_memory; } else { switch (*endptr){ case 'Y': membuf *= 1024; /* FALLTHROUGH */ case 'Z': membuf *= 1024; /* FALLTHROUGH */ case 'E': membuf *= 1024; /* FALLTHROUGH */ case 'P': membuf *= 1024; /* FALLTHROUGH */ case 'T': membuf *= 1024; /* FALLTHROUGH */ case 'G': membuf *= 1024; /* FALLTHROUGH */ case 'M': membuf *= 1024; /* FALLTHROUGH */ case '\0': case 'K': membuf *= 1024; /* FALLTHROUGH */ case 'b': break; case '%': membuf = (available_free_memory * membuf) / 100; break; default: warnc(EINVAL, "%s", optarg); membuf = available_free_memory; } } return (membuf); } }
int main(int argc, char *argv[]) { const char *ifname; char *driver; int error; bool ok; while (getopt(argc, argv, "") != -1) usage(); argc -= optind; argv += optind; if (argc == 0) usage(); if (argc == 1) { error = ifname2drivername(*argv, &driver); if (error != 0) errc(1, error, "ifname2drivername"); printf("%s\n", driver); free(driver); return (0); } ok = true; while (argc--) { ifname = *argv++; error = ifname2drivername(ifname, &driver); if (error != 0) { warnc(error, "ifname2drivername(\"%s\")", ifname); ok = false; continue; } printf("%s: %s\n", ifname, driver); free(driver); } if (!ok) return (1); return (0); }
int connect_to_pccardd(char **path) { int so = -1; int pccardd_len; struct sockaddr_un pccardq; struct sockaddr_un pccardd; if ((so = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) { warn("socket"); goto err; } snprintf(pccardq.sun_path, sizeof pccardq.sun_path, "%s/%s%ld%ld", tmp_dir, prog, (long) getpid(), (long) time(0)); pccardq.sun_family = AF_UNIX; pccardq.sun_len = offsetof(struct sockaddr_un, sun_path) + strlen(pccardq.sun_path); if (bind(so, (struct sockaddr *) &pccardq, pccardq.sun_len) < 0) { warn("bind: %s", pccardq.sun_path); goto err; } if ((*path = strdup(pccardq.sun_path)) == NULL) { warn("strdup"); goto err; } pccardd_len = strlen(pccardd_file) + 1; if (pccardd_len > sizeof pccardd.sun_path) { warnc(0, "%s: too long", pccardd_file); goto err; } pccardd.sun_len = offsetof(struct sockaddr_un, sun_path) + pccardd_len; pccardd.sun_family = AF_UNIX; strcpy(pccardd.sun_path, pccardd_file); if (connect(so, (struct sockaddr *) &pccardd, pccardd.sun_len) < 0) { warn("connect: %s", pccardd_file); goto err; } return so; err: if (so >= 0) close(so); return -1; }
int proc_arg(int ac, char **av) { int rc = -1; int ch; char *p = strrchr(av[0], '/'); prog = p ? p + 1 : av[0]; tmp_dir = getenv("TMPDIR") ? getenv("TMPDIR") : tmp_dir; while ((ch = getopt(ac, av, "ans:")) != -1) { switch (ch) { case 'a': slot_map = ~0; break; case 'n': slot_map = 0; break; case 's': { int n = atoi(optarg); if (n < 0 || n >= CHAR_BIT * sizeof slot_map) { warnc(0, "Invalid slot number."); usage(); goto out; } if (slot_map == ~0) slot_map = 0; slot_map |= 1 << n; } break; default: usage(); goto out; } } rc = 0; out: return rc; }
int create_knlist(char *name, int fd, DB *db) { int error, ksyms; if (strcmp(name, _PATH_KSYMS) == 0) { ksyms = 1; } else { ksyms = 0; } fmterr = NULL; kfile = name; /* rval of 1 means wrong executable type */ error = __elf_knlist(fd, db, ksyms); if (fmterr != NULL) warnc(EFTYPE, "%s: %s", kfile, fmterr); return(error); }
static void cleanup(void) { if (NULL != buffer) { free(buffer); buffer = NULL; } if (NULL != ctxt) { if (NULL != engine->close) { engine->close(ctxt); } free(ctxt); ctxt = NULL; } queue_close(&queue); if (NULL != pidfilename) { if (0 != unlink(pidfilename)) { warnc("unlink failed"); } } if (NULL != err_file && fileno(err_file) > 2) { fclose(err_file); err_file = NULL; } }
/* * Diff directory traversal. Will be called recursively if -r was specified. */ void diffdir(char *p1, char *p2, int flags) { struct dirent *dent1, **dp1, **edp1, **dirp1 = NULL; struct dirent *dent2, **dp2, **edp2, **dirp2 = NULL; size_t dirlen1, dirlen2; char path1[MAXPATHLEN], path2[MAXPATHLEN]; int pos; dirlen1 = strlcpy(path1, *p1 ? p1 : ".", sizeof(path1)); if (dirlen1 >= sizeof(path1) - 1) { warnc(ENAMETOOLONG, "%s", p1); status = 2; return; } if (path1[dirlen1 - 1] != '/') { path1[dirlen1++] = '/'; path1[dirlen1] = '\0'; } dirlen2 = strlcpy(path2, *p2 ? p2 : ".", sizeof(path2)); if (dirlen2 >= sizeof(path2) - 1) { warnc(ENAMETOOLONG, "%s", p2); status = 2; return; } if (path2[dirlen2 - 1] != '/') { path2[dirlen2++] = '/'; path2[dirlen2] = '\0'; } /* * Get a list of entries in each directory, skipping "excluded" files * and sorting alphabetically. */ pos = scandir(path1, &dirp1, selectfile, alphasort); if (pos == -1) { if (errno == ENOENT && (Nflag || Pflag)) { pos = 0; } else { warn("%s", path1); goto closem; } } dp1 = dirp1; edp1 = dirp1 + pos; pos = scandir(path2, &dirp2, selectfile, alphasort); if (pos == -1) { if (errno == ENOENT && Nflag) { pos = 0; } else { warn("%s", path2); goto closem; } } dp2 = dirp2; edp2 = dirp2 + pos; /* * If we were given a starting point, find it. */ if (start != NULL) { while (dp1 != edp1 && strcmp((*dp1)->d_name, start) < 0) dp1++; while (dp2 != edp2 && strcmp((*dp2)->d_name, start) < 0) dp2++; } /* * Iterate through the two directory lists, diffing as we go. */ while (dp1 != edp1 || dp2 != edp2) { dent1 = dp1 != edp1 ? *dp1 : NULL; dent2 = dp2 != edp2 ? *dp2 : NULL; pos = dent1 == NULL ? 1 : dent2 == NULL ? -1 : strcmp(dent1->d_name, dent2->d_name); if (pos == 0) { /* file exists in both dirs, diff it */ diffit(dent1, path1, dirlen1, path2, dirlen2, flags); dp1++; dp2++; } else if (pos < 0) { /* file only in first dir, only diff if -N */ if (Nflag) diffit(dent1, path1, dirlen1, path2, dirlen2, flags); else if (lflag) dent1->d_status |= D_ONLY; else print_only(path1, dirlen1, dent1->d_name); dp1++; } else { /* file only in second dir, only diff if -N or -P */ if (Nflag || Pflag) diffit(dent2, path1, dirlen1, path2, dirlen2, flags); else if (lflag) dent2->d_status |= D_ONLY; else print_only(path2, dirlen2, dent2->d_name); dp2++; } } if (lflag) { path1[dirlen1] = '\0'; path2[dirlen2] = '\0'; for (dp1 = dirp1; (dent1 = *dp1) != NULL; dp1++) { print_status(dent1->d_status, path1, path2, dent1->d_name); } for (dp2 = dirp2; (dent2 = *dp2) != NULL; dp2++) { if (dent2->d_status == D_ONLY) print_status(dent2->d_status, path2, NULL, dent2->d_name); } } closem: if (dirp1 != NULL) { for (dp1 = dirp1; dp1 < edp1; dp1++) xfree(*dp1); xfree(dirp1); } if (dirp2 != NULL) { for (dp2 = dirp2; dp2 < edp2; dp2++) xfree(*dp2); xfree(dirp2); } }
int main(int argc, char *argv[]) { FTS *ftsp; FTSENT *p; void *set; unsigned long val; int oct; mode_t omode; int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, atflags; uid_t uid; gid_t gid; u_int32_t fclear, fset; char *ep, *mode, *cp, *flags; if (strlen(__progname) > 2) { ischown = __progname[2] == 'o'; ischgrp = __progname[2] == 'g'; ischmod = __progname[2] == 'm'; ischflags = __progname[2] == 'f'; } uid = (uid_t)-1; gid = (gid_t)-1; Hflag = Lflag = Rflag = fflag = hflag = 0; while ((ch = getopt(argc, argv, "HLPRXfghorstuwx")) != -1) switch (ch) { case 'H': Hflag = 1; Lflag = 0; break; case 'L': Lflag = 1; Hflag = 0; break; case 'P': Hflag = Lflag = 0; break; case 'R': Rflag = 1; break; case 'f': /* no longer documented. */ fflag = 1; break; case 'h': hflag = 1; break; /* * If this is a symbolic mode argument rather than * an option, we are done with option processing. */ case 'g': case 'o': case 'r': case 's': case 't': case 'u': case 'w': case 'X': case 'x': if (!ischmod) usage(); /* * If getopt() moved past the argument, back up. * If the argument contains option letters before * mode letters, setmode() will catch them. */ if (optind > 1) { cp = argv[optind - 1]; if (cp[strlen(cp) - 1] == ch) --optind; } goto done; default: usage(); } done: argv += optind; argc -= optind; if (argc < 2) usage(); /* * We alter the symlink itself if doing -h or -RP, or * if doing -RH and the symlink wasn't a command line arg. */ atflags = AT_SYMLINK_NOFOLLOW; fts_options = FTS_PHYSICAL; if (Rflag) { if (hflag) errx(1, "the -R and -h options may not be specified together."); if (Hflag) fts_options |= FTS_COMFOLLOW; if (Lflag) { fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; atflags = 0; } } else if (!hflag) { fts_options |= FTS_COMFOLLOW; atflags = 0; } if (ischflags) { if (pledge("stdio rpath fattr", NULL) == -1) err(1, "pledge"); flags = *argv; if (*flags >= '0' && *flags <= '7') { errno = 0; val = strtoul(flags, &ep, 8); if (val > UINT_MAX) errno = ERANGE; if (errno) err(1, "invalid flags: %s", flags); if (*ep) errx(1, "invalid flags: %s", flags); fset = val; oct = 1; } else { if (strtofflags(&flags, &fset, &fclear)) errx(1, "invalid flag: %s", flags); fclear = ~fclear; oct = 0; } } else if (ischmod) { mode = *argv; if (*mode >= '0' && *mode <= '7') { errno = 0; val = strtoul(mode, &ep, 8); if (val > INT_MAX) errno = ERANGE; if (errno) err(1, "invalid file mode: %s", mode); if (*ep) errx(1, "invalid file mode: %s", mode); omode = val; oct = 1; } else { if ((set = setmode(mode)) == NULL) errx(1, "invalid file mode: %s", mode); oct = 0; } } else if (ischown) { /* Both UID and GID are given. */ if ((cp = strchr(*argv, ':')) != NULL) { *cp++ = '\0'; gid = a_gid(cp); } /* * UID and GID are separated by a dot and UID exists. * required for backwards compatibility pre-dating POSIX.2 * likely to stay here forever */ else if ((cp = strchr(*argv, '.')) != NULL && (uid = a_uid(*argv, 1)) == (uid_t)-1) { *cp++ = '\0'; gid = a_gid(cp); } if (uid == (uid_t)-1) uid = a_uid(*argv, 0); } else gid = a_gid(*argv); if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) err(1, NULL); for (rval = 0; (p = fts_read(ftsp)) != NULL;) { switch (p->fts_info) { case FTS_D: if (!Rflag) fts_set(ftsp, p, FTS_SKIP); if (ischmod) break; else continue; case FTS_DNR: /* Warn, chmod, continue. */ warnc(p->fts_errno, "%s", p->fts_path); rval = 1; break; case FTS_DP: /* Already changed at FTS_D. */ if (ischmod) continue; else break; case FTS_ERR: /* Warn, continue. */ case FTS_NS: warnc(p->fts_errno, "%s", p->fts_path); rval = 1; continue; case FTS_SL: /* Ignore. */ case FTS_SLNONE: /* * The only symlinks that end up here are ones that * don't point to anything or that loop and ones * that we found doing a physical walk. */ if (!hflag && (fts_options & FTS_LOGICAL)) continue; break; default: break; } /* * For -RH, the decision of how to handle symlinks depends * on the level: follow it iff it's a command line arg. */ if (fts_options & FTS_COMFOLLOW) { atflags = p->fts_level == FTS_ROOTLEVEL ? 0 : AT_SYMLINK_NOFOLLOW; } if (ischmod) { if (!fchmodat(AT_FDCWD, p->fts_accpath, oct ? omode : getmode(set, p->fts_statp->st_mode), atflags) || fflag) continue; } else if (!ischflags) { if (!fchownat(AT_FDCWD, p->fts_accpath, uid, gid, atflags) || fflag) continue; } else { if (!chflagsat(AT_FDCWD, p->fts_accpath, oct ? fset : (p->fts_statp->st_flags | fset) & fclear, atflags)) continue; } /* error case */ warn("%s", p->fts_path); rval = 1; } if (errno) err(1, "fts_read"); fts_close(ftsp); return (rval); }
int ruserpass(const char *host, char **aname, char **apass, char **aacct) { char *hdir, buf[MAXPATHLEN], *tmp; char myname[MAXHOSTNAMELEN], *mydomain; int t, i, c, usedefault = 0; struct stat stb; hdir = getenv("HOME"); if (hdir == NULL || *hdir == '\0') return (0); i = snprintf(buf, sizeof(buf), "%s/.netrc", hdir); if (i < 0 || i >= sizeof(buf)) { warnc(ENAMETOOLONG, "%s/.netrc", hdir); return (0); } cfile = fopen(buf, "r"); if (cfile == NULL) { if (errno != ENOENT) warn("%s", buf); return (0); } if (gethostname(myname, sizeof(myname)) < 0) myname[0] = '\0'; if ((mydomain = strchr(myname, '.')) == NULL) mydomain = ""; next: while ((t = token()) > 0) switch(t) { case DEFAULT: usedefault = 1; /* FALLTHROUGH */ case MACH: if (!usedefault) { if ((t = token()) == -1) goto bad; if (t != ID) continue; /* * Allow match either for user's input host name * or official hostname. Also allow match of * incompletely-specified host in local domain. */ if (strcasecmp(host, tokval) == 0) goto match; if (strcasecmp(hostname, tokval) == 0) goto match; if ((tmp = strchr(hostname, '.')) != NULL && strcasecmp(tmp, mydomain) == 0 && strncasecmp(hostname, tokval, (size_t)(tmp - hostname)) == 0 && tokval[tmp - hostname] == '\0') goto match; if ((tmp = strchr(host, '.')) != NULL && strcasecmp(tmp, mydomain) == 0 && strncasecmp(host, tokval, (size_t)(tmp - host)) == 0 && tokval[tmp - host] == '\0') goto match; continue; } match: while ((t = token()) > 0 && t != MACH && t != DEFAULT) switch(t) { case LOGIN: if ((t = token()) == -1) goto bad; if (t) { if (*aname == 0) { if ((*aname = strdup(tokval)) == NULL) err(1, "strdup"); } else { if (strcmp(*aname, tokval)) goto next; } } break; case PASSWD: if ((*aname == NULL || strcmp(*aname, "anonymous")) && fstat(fileno(cfile), &stb) >= 0 && (stb.st_mode & 077) != 0) { warnx("Error: .netrc file is readable by others."); warnx("Remove password or make file unreadable by others."); goto bad; } if ((t = token()) == -1) goto bad; if (t && *apass == 0) { if ((*apass = strdup(tokval)) == NULL) err(1, "strdup"); } break; case ACCOUNT: if (fstat(fileno(cfile), &stb) >= 0 && (stb.st_mode & 077) != 0) { warnx("Error: .netrc file is readable by others."); warnx("Remove account or make file unreadable by others."); goto bad; } if ((t = token()) == -1) goto bad; if (t && *aacct == 0) { if ((*aacct = strdup(tokval)) == NULL) err(1, "strdup"); } break; case MACDEF: if (proxy) { (void)fclose(cfile); return (0); } while ((c = fgetc(cfile)) != EOF) if (c != ' ' && c != '\t') break; if (c == EOF || c == '\n') { fputs("Missing macdef name argument.\n", ttyout); goto bad; } if (macnum == 16) { fputs( "Limit of 16 macros have already been defined.\n", ttyout); goto bad; } tmp = macros[macnum].mac_name; *tmp++ = c; for (i=0; i < 8 && (c = fgetc(cfile)) != EOF && !isspace(c); ++i) { *tmp++ = c; } if (c == EOF) { fputs( "Macro definition missing null line terminator.\n", ttyout); goto bad; } *tmp = '\0'; if (c != '\n') { while ((c = fgetc(cfile)) != EOF && c != '\n'); } if (c == EOF) { fputs( "Macro definition missing null line terminator.\n", ttyout); goto bad; } if (macnum == 0) { macros[macnum].mac_start = macbuf; } else { macros[macnum].mac_start = macros[macnum-1].mac_end + 1; } tmp = macros[macnum].mac_start; while (tmp != macbuf + 4096) { if ((c = fgetc(cfile)) == EOF) { fputs( "Macro definition missing null line terminator.\n", ttyout); goto bad; } *tmp = c; if (*tmp == '\n') { if (tmp == macros[macnum].mac_start) { macros[macnum++].mac_end = tmp; break; } else if (*(tmp-1) == '\0') { macros[macnum++].mac_end = tmp - 1; break; } *tmp = '\0'; } tmp++; } if (tmp == macbuf + 4096) { fputs("4K macro buffer exceeded.\n", ttyout); goto bad; } break; default: warnx("Unknown .netrc keyword %s", tokval); break; } goto done; } done: if (t == -1) goto bad; (void)fclose(cfile); return (0); bad: (void)fclose(cfile); return (-1); }
static void process_select(fd_set *rfds, fd_set *wfds, fd_set *efds) { unsigned int i = 0; while (i < num_flows) { struct _flow *flow = &flows[i]; DEBUG_MSG(LOG_DEBUG, "processing pselect() for flow %d", flow->id); if (flow->listenfd_data != -1 && FD_ISSET(flow->listenfd_data, rfds)) { DEBUG_MSG(LOG_DEBUG, "ready for accept"); if (flow->state == GRIND_WAIT_ACCEPT) { if (accept_data(flow) == -1) { DEBUG_MSG(LOG_ERR, "accept_data() " "failed"); goto remove; } } } if (flow->fd != -1) { if (FD_ISSET(flow->fd, efds)) { int error_number, rc; socklen_t error_number_size = sizeof(error_number); DEBUG_MSG(LOG_DEBUG, "sock of flow %d in efds", flow->id); rc = getsockopt(flow->fd, SOL_SOCKET, SO_ERROR, (void *)&error_number, &error_number_size); if (rc == -1) { warn("failed to get errno for" "non-blocking connect"); goto remove; } if (error_number != 0) { warnc(error_number, "connect"); goto remove; } } if (FD_ISSET(flow->fd, wfds)) if (write_data(flow) == -1) { DEBUG_MSG(LOG_ERR, "write_data() failed"); goto remove; } if (FD_ISSET(flow->fd, rfds)) if (read_data(flow) == -1) { DEBUG_MSG(LOG_ERR, "read_data() failed"); goto remove; } } i++; continue; remove: if (flow->fd != -1) { flow->statistics[FINAL].has_tcp_info = get_tcp_info(flow, &flow->statistics[FINAL].tcp_info) ? 0 : 1; } flow->pmtu = get_pmtu(flow->fd); report_flow(flow, FINAL); uninit_flow(flow); remove_flow(i); DEBUG_MSG(LOG_ERR, "removed flow %d", flow->id); } }
int fastcopy(char *from, char *to, struct stat *sbp) { struct timespec ts[2]; static u_int32_t blen; static char *bp; int nread, from_fd, to_fd; int badchown = 0, serrno = 0; if (!blen) { blen = sbp->st_blksize; if ((bp = malloc(blen)) == NULL) { warn(NULL); blen = 0; return (1); } } if ((from_fd = open(from, O_RDONLY, 0)) < 0) { warn("%s", from); return (1); } if ((to_fd = open(to, O_CREAT | O_TRUNC | O_WRONLY, 0600)) < 0) { warn("%s", to); (void)close(from_fd); return (1); } if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) { serrno = errno; badchown = 1; } (void) fchmod(to_fd, sbp->st_mode & ~(S_ISUID|S_ISGID)); while ((nread = read(from_fd, bp, blen)) > 0) if (write(to_fd, bp, nread) != nread) { warn("%s", to); goto err; } if (nread < 0) { warn("%s", from); err: if (unlink(to)) warn("%s: remove", to); (void)close(from_fd); (void)close(to_fd); return (1); } (void)close(from_fd); if (badchown) { if ((sbp->st_mode & (S_ISUID|S_ISGID))) { warnc(serrno, "%s: set owner/group; not setting setuid/setgid", to); sbp->st_mode &= ~(S_ISUID|S_ISGID); } else if (!fflg) warnc(serrno, "%s: set owner/group", to); } if (fchmod(to_fd, sbp->st_mode)) warn("%s: set mode", to); /* * XXX * NFS doesn't support chflags; ignore errors unless there's reason * to believe we're losing bits. (Note, this still won't be right * if the server supports flags and we were trying to *remove* flags * on a file that we copied, i.e., that we didn't create.) */ errno = 0; if (fchflags(to_fd, sbp->st_flags)) if (errno != EOPNOTSUPP || sbp->st_flags != 0) warn("%s: set flags", to); ts[0] = sbp->st_atim; ts[1] = sbp->st_mtim; if (futimens(to_fd, ts)) warn("%s: set times", to); if (close(to_fd)) { warn("%s", to); return (1); } if (unlink(from)) { warn("%s: remove", from); return (1); } if (vflg) (void)fprintf(stdout, "%s -> %s\n", from, to); return (0); }
static int video_mode(int argc, char **argv, int *mode_index) { static struct { const char *name; unsigned long mode; unsigned long mode_num; } modes[] = { { "80x25", SW_TEXT_80x25, M_TEXT_80x25 }, { "80x30", SW_TEXT_80x30, M_TEXT_80x30 }, { "80x43", SW_TEXT_80x43, M_TEXT_80x43 }, { "80x50", SW_TEXT_80x50, M_TEXT_80x50 }, { "80x60", SW_TEXT_80x60, M_TEXT_80x60 }, { "132x25", SW_TEXT_132x25, M_TEXT_132x25 }, { "132x30", SW_TEXT_132x30, M_TEXT_132x30 }, { "132x43", SW_TEXT_132x43, M_TEXT_132x43 }, { "132x50", SW_TEXT_132x50, M_TEXT_132x50 }, { "132x60", SW_TEXT_132x60, M_TEXT_132x60 }, { "VGA_40x25", SW_VGA_C40x25, M_VGA_C40x25 }, { "VGA_80x25", SW_VGA_C80x25, M_VGA_C80x25 }, { "VGA_80x30", SW_VGA_C80x30, M_VGA_C80x30 }, { "VGA_80x50", SW_VGA_C80x50, M_VGA_C80x50 }, { "VGA_80x60", SW_VGA_C80x60, M_VGA_C80x60 }, #ifdef SW_VGA_C90x25 { "VGA_90x25", SW_VGA_C90x25, M_VGA_C90x25 }, { "VGA_90x30", SW_VGA_C90x30, M_VGA_C90x30 }, { "VGA_90x43", SW_VGA_C90x43, M_VGA_C90x43 }, { "VGA_90x50", SW_VGA_C90x50, M_VGA_C90x50 }, { "VGA_90x60", SW_VGA_C90x60, M_VGA_C90x60 }, #endif { "VGA_320x200", SW_VGA_CG320, M_CG320 }, { "EGA_80x25", SW_ENH_C80x25, M_ENH_C80x25 }, { "EGA_80x43", SW_ENH_C80x43, M_ENH_C80x43 }, { "VESA_132x25", SW_VESA_C132x25,M_VESA_C132x25 }, { "VESA_132x43", SW_VESA_C132x43,M_VESA_C132x43 }, { "VESA_132x50", SW_VESA_C132x50,M_VESA_C132x50 }, { "VESA_132x60", SW_VESA_C132x60,M_VESA_C132x60 }, { "VESA_800x600", SW_VESA_800x600,M_VESA_800x600 }, { NULL, 0, 0 }, }; int new_mode_num = 0; unsigned long mode = 0; int cur_mode; int ioerr; int size[3]; int i; if (ioctl(0, CONS_GET, &cur_mode) < 0) err(1, "cannot get the current video mode"); /* * Parse the video mode argument... */ if (*mode_index < argc) { if (!strncmp(argv[*mode_index], "MODE_", 5)) { if (!isdigit(argv[*mode_index][5])) errx(1, "invalid video mode number"); new_mode_num = atoi(&argv[*mode_index][5]); } else { for (i = 0; modes[i].name != NULL; ++i) { if (!strcmp(argv[*mode_index], modes[i].name)) { mode = modes[i].mode; new_mode_num = modes[i].mode_num; break; } } if (modes[i].name == NULL) return EXIT_FAILURE; if (ioctl(0, mode, NULL) < 0) { warn("cannot set videomode"); return EXIT_FAILURE; } } /* * Collect enough information about the new video mode... */ new_mode_info.vi_mode = new_mode_num; if (ioctl(0, CONS_MODEINFO, &new_mode_info) == -1) { revert(); errc(1, errno, "obtaining new video mode parameters"); } if (mode == 0) { if (new_mode_num >= M_VESA_BASE) mode = _IO('V', new_mode_num - M_VESA_BASE); else mode = _IO('S', new_mode_num); } /* * Try setting the new mode. */ if (ioctl(0, mode, NULL) == -1) { revert(); errc(1, errno, "setting video mode"); } /* * For raster modes it's not enough to just set the mode. * We also need to explicitly set the raster mode. */ if (new_mode_info.vi_flags & V_INFO_GRAPHICS) { /* font size */ if (font_height == 0) font_height = cur_info.console_info.font_size; size[2] = font_height; /* adjust columns */ if ((vesa_cols * 8 > new_mode_info.vi_width) || (vesa_cols <= 0)) { size[0] = new_mode_info.vi_width / 8; } else { size[0] = vesa_cols; } /* adjust rows */ if ((vesa_rows * font_height > new_mode_info.vi_height) || (vesa_rows <= 0)) { size[1] = new_mode_info.vi_height / font_height; } else { size[1] = vesa_rows; } /* set raster mode */ if (ioctl(0, KDRASTER, size)) { ioerr = errno; if (cur_mode >= M_VESA_BASE) ioctl(0, _IO('V', cur_mode - M_VESA_BASE), NULL); else ioctl(0, _IO('S', cur_mode), NULL); revert(); warnc(ioerr, "cannot activate raster display"); return EXIT_FAILURE; } } video_mode_changed = 1; (*mode_index)++; } return EXIT_SUCCESS; }
/* * Set the date in the machines controlled by timedaemons by communicating the * new date to the local timedaemon. If the timedaemon is in the master state, * it performs the correction on all slaves. If it is in the slave state, it * notifies the master that a correction is needed. * Returns 0 on success. Returns > 0 on failure, setting retval to 2; */ int netsettime(time_t tval) { struct timeval tout; struct servent *sp; struct tsp msg; struct sockaddr_in lsin, dest, from; fd_set ready; long waittime; int s, port, timed_ack, found, lerr; socklen_t length; char hostname[MAXHOSTNAMELEN]; if ((sp = getservbyname("timed", "udp")) == NULL) { warnx("timed/udp: unknown service"); return (retval = 2); } dest.sin_port = sp->s_port; dest.sin_family = AF_INET; dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { if (errno != EPROTONOSUPPORT) warn("timed"); return (retval = 2); } memset(&lsin, 0, sizeof(lsin)); lsin.sin_family = AF_INET; for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { lsin.sin_port = htons((u_short)port); if (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0) break; if (errno == EADDRINUSE) continue; if (errno != EADDRNOTAVAIL) warn("bind"); goto bad; } if (port == IPPORT_RESERVED / 2) { warnx("all ports in use"); goto bad; } msg.tsp_type = TSP_SETDATE; msg.tsp_vers = TSPVERSION; if (gethostname(hostname, sizeof(hostname))) { warn("gethostname"); goto bad; } (void)strncpy(msg.tsp_name, hostname, sizeof(msg.tsp_name) - 1); msg.tsp_name[sizeof(msg.tsp_name) - 1] = '\0'; msg.tsp_seq = htons((u_short)0); msg.tsp_time.tv_sec = htonl((u_long)tval); msg.tsp_time.tv_usec = htonl((u_long)0); length = sizeof(struct sockaddr_in); if (connect(s, (struct sockaddr *)&dest, length) < 0) { warn("connect"); goto bad; } if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) { if (errno != ECONNREFUSED) warn("send"); goto bad; } timed_ack = -1; waittime = WAITACK; loop: tout.tv_sec = waittime; tout.tv_usec = 0; FD_ZERO(&ready); FD_SET(s, &ready); found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout); length = sizeof(lerr); if (!getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) { if (lerr != ECONNREFUSED) warnc(lerr, "send (delayed error)"); goto bad; } if (found > 0 && FD_ISSET(s, &ready)) { length = sizeof(struct sockaddr_in); if (recvfrom(s, &msg, sizeof(struct tsp), 0, (struct sockaddr *)&from, &length) < 0) { if (errno != ECONNREFUSED) warn("recvfrom"); goto bad; } msg.tsp_seq = ntohs(msg.tsp_seq); msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec); msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec); switch (msg.tsp_type) { case TSP_ACK: timed_ack = TSP_ACK; waittime = WAITDATEACK; goto loop; case TSP_DATEACK: (void)close(s); return (0); default: warnx("wrong ack received from timed: %s", tsptype[msg.tsp_type]); timed_ack = -1; break; } } if (timed_ack == -1) warnx("can't reach time daemon, time set locally"); bad: (void)close(s); return (retval = 2); }
int main(int argc, char *argv[]) { const char *errstr; char errbuf[_POSIX2_LINE_MAX], *kmem = NULL, *kernel = NULL; struct kinfo_proc *kproc; struct sum total_sum; int many, ch, rc; kvm_t *kd; pid_t pid = -1; gid_t gid; while ((ch = getopt(argc, argv, "AaD:dlmM:N:p:Prsvx")) != -1) { switch (ch) { case 'A': print_amap = 1; break; case 'a': print_all = 1; break; case 'd': print_ddb = 1; break; case 'D': debug = strtonum(optarg, 0, 0xf, &errstr); if (errstr) errx(1, "invalid debug mask"); break; case 'l': print_maps = 1; break; case 'm': print_map = 1; break; case 'M': kmem = optarg; break; case 'N': kernel = optarg; break; case 'p': pid = strtopid(optarg); break; case 'P': pid = getpid(); break; case 's': print_solaris = 1; break; case 'v': verbose = 1; break; case 'r': case 'x': errx(1, "-%c option not implemented, sorry", ch); /*NOTREACHED*/ default: usage(); } } /* * Discard setgid privileges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ gid = getgid(); if (kernel != NULL || kmem != NULL) if (setresgid(gid, gid, gid) == -1) err(1, "setresgid"); argc -= optind; argv += optind; /* more than one "process" to dump? */ many = (argc > 1 - (pid == -1 ? 0 : 1)) ? 1 : 0; /* apply default */ if (print_all + print_map + print_maps + print_solaris + print_ddb == 0) print_solaris = 1; /* start by opening libkvm */ kd = kvm_openfiles(kernel, kmem, NULL, O_RDONLY, errbuf); if (kernel == NULL && kmem == NULL) if (setresgid(gid, gid, gid) == -1) err(1, "setresgid"); if (kd == NULL) errx(1, "%s", errbuf); /* get "bootstrap" addresses from kernel */ load_symbols(kd); memset(&total_sum, 0, sizeof(total_sum)); do { struct sum sum; memset(&sum, 0, sizeof(sum)); if (pid == -1) { if (argc == 0) pid = getppid(); else { pid = strtopid(argv[0]); argv++; argc--; } } /* find the process id */ if (pid == 0) kproc = NULL; else { kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &rc); if (kproc == NULL || rc == 0) { warnc(ESRCH, "%d", pid); pid = -1; continue; } } /* dump it */ if (many) { if (kproc) printf("process %d:\n", pid); else printf("kernel:\n"); } process_map(kd, pid, kproc, &sum); if (print_amap) print_sum(&sum, &total_sum); pid = -1; } while (argc > 0); if (print_amap) print_sum(&total_sum, NULL); /* done. go away. */ rc = kvm_close(kd); if (rc == -1) err(1, "kvm_close"); return (0); }
static int writelabel(void) { int i, fd, serrno; struct gctl_req *grq; char const *errstr; struct disklabel *lp = &lab; if (disable_write) { warnx("write to disk label suppressed - label was as follows:"); display(stdout, NULL); return (0); } lp->d_magic = DISKMAGIC; lp->d_magic2 = DISKMAGIC; lp->d_checksum = 0; lp->d_checksum = dkcksum(lp); if (installboot) readboot(); for (i = 0; i < lab.d_npartitions; i++) if (lab.d_partitions[i].p_size) lab.d_partitions[i].p_offset += lba_offset; bsd_disklabel_le_enc(bootarea + labeloffset + labelsoffset * lab.d_secsize, lp); fd = open(specname, O_RDWR); if (fd < 0) { if (is_file) { warn("cannot open file %s for writing label", specname); return(1); } else serrno = errno; if (geom_class_available("PART") != 0) { /* * Since we weren't able open provider for * writing, then recommend user to use gpart(8). */ warnc(serrno, "cannot open provider %s for writing label", specname); warnx("Try to use gpart(8)."); return (1); } /* Give up if GEOM_BSD is not available. */ if (geom_class_available("BSD") == 0) { warnc(serrno, "%s", specname); return (1); } grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write label"); gctl_ro_param(grq, "class", -1, "BSD"); gctl_ro_param(grq, "geom", -1, pname); gctl_ro_param(grq, "label", 148+16*8, bootarea + labeloffset + labelsoffset * lab.d_secsize); errstr = gctl_issue(grq); if (errstr != NULL) { warnx("%s", errstr); gctl_free(grq); return(1); } gctl_free(grq); if (installboot) { grq = gctl_get_handle(); gctl_ro_param(grq, "verb", -1, "write bootcode"); gctl_ro_param(grq, "class", -1, "BSD"); gctl_ro_param(grq, "geom", -1, pname); gctl_ro_param(grq, "bootcode", BBSIZE, bootarea); errstr = gctl_issue(grq); if (errstr != NULL) { warnx("%s", errstr); gctl_free(grq); return (1); } gctl_free(grq); } } else { if (write(fd, bootarea, bbsize) != bbsize) { warn("write %s", specname); close (fd); return (1); } close (fd); } return (0); }
/* * Nomenclature warning! * * In this source "target" and "source" are used the opposite way they * are used in the ln(1) manual. Here "target" is the existing file and * "source" specifies the to-be-created link to "target". */ int linkit(char *target, char *source, int isdir) { struct stat sb; char *p, path[PATH_MAX]; int (*statf)(const char *, struct stat *); int exists, n; if (!sflag) { /* If target doesn't exist, quit now. */ if ((Pflag ? lstat : stat)(target, &sb)) { warn("%s", target); return (1); } /* Only symbolic links to directories. */ if (S_ISDIR(sb.st_mode)) { warnc(EISDIR, "%s", target); return (1); } } statf = hflag ? lstat : stat; /* If the source is a directory, append the target's name. */ if (isdir || (!statf(source, &sb) && S_ISDIR(sb.st_mode))) { if ((p = basename(target)) == NULL) { warn("%s", target); return (1); } n = snprintf(path, sizeof(path), "%s/%s", source, p); if (n < 0 || n >= sizeof(path)) { warnc(ENAMETOOLONG, "%s/%s", source, p); return (1); } source = path; } exists = (lstat(source, &sb) == 0); /* * If doing hard links and the source (destination) exists and it * actually is the same file like the target (existing file), we * complain that the files are identical. If -f is specified, we * accept the job as already done and return with success. */ if (exists && !sflag) { struct stat tsb; if ((Pflag ? lstat : stat)(target, &tsb)) { warn("%s: disappeared", target); return (1); } if (tsb.st_dev == sb.st_dev && tsb.st_ino == sb.st_ino) { if (fflag) return (0); else { warnx("%s and %s are identical (nothing done).", target, source); return (1); } } } /* * If the file exists, and -f was specified, unlink it. * Attempt the link. */ if ((fflag && unlink(source) < 0 && errno != ENOENT) || sflag ? symlink(target, source) : linkat(AT_FDCWD, target, AT_FDCWD, source, Pflag ? 0 : AT_SYMLINK_FOLLOW)) { warn("%s", source); return (1); } return (0); }
int getnfsargs(char *spec, struct nfs_args *nfsargsp) { CLIENT *clp; struct hostent *hp; static struct sockaddr_in saddr; struct timeval pertry, try; enum clnt_stat clnt_stat; int so = RPC_ANYSOCK, i, nfsvers, mntvers, orgcnt; char *hostp, *delimp; u_short tport; static struct nfhret nfhret; static char nam[MNAMELEN + 1]; if (strlcpy(nam, spec, sizeof(nam)) >= sizeof(nam)) { errx(1, "hostname too long"); } if ((delimp = strchr(spec, '@')) != NULL) { hostp = delimp + 1; } else if ((delimp = strchr(spec, ':')) != NULL) { hostp = spec; spec = delimp + 1; } else { warnx("no <host>:<dirpath> or <dirpath>@<host> spec"); return (0); } *delimp = '\0'; /* * Handle an internet host address */ if (inet_aton(hostp, &saddr.sin_addr) == 0) { hp = gethostbyname(hostp); if (hp == NULL) { warnx("can't resolve address for host %s", hostp); return (0); } memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length); } if (force2) { nfsvers = NFS_VER2; mntvers = RPCMNT_VER1; } else { nfsvers = NFS_VER3; mntvers = RPCMNT_VER3; } orgcnt = retrycnt; tryagain: nfhret.stat = EACCES; /* Mark not yet successful */ while (retrycnt > 0) { saddr.sin_family = AF_INET; saddr.sin_port = htons(PMAPPORT); if ((tport = port_no ? port_no : pmap_getport(&saddr, RPCPROG_NFS, nfsvers, nfsargsp->sotype == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP)) == 0) { if ((opflags & ISBGRND) == 0) clnt_pcreateerror("NFS Portmap"); } else { saddr.sin_port = 0; pertry.tv_sec = 10; pertry.tv_usec = 0; if (mnttcp_ok && nfsargsp->sotype == SOCK_STREAM) clp = clnttcp_create(&saddr, RPCPROG_MNT, mntvers, &so, 0, 0); else clp = clntudp_create(&saddr, RPCPROG_MNT, mntvers, pertry, &so); if (clp == NULL) { if ((opflags & ISBGRND) == 0) clnt_pcreateerror("Cannot MNT RPC"); } else { clp->cl_auth = authunix_create_default(); try.tv_sec = 10; try.tv_usec = 0; nfhret.auth = RPCAUTH_UNIX; nfhret.vers = mntvers; clnt_stat = clnt_call(clp, RPCMNT_MOUNT, xdr_dir, spec, xdr_fh, &nfhret, try); if (clnt_stat != RPC_SUCCESS) { if (clnt_stat == RPC_PROGVERSMISMATCH) { if (nfsvers == NFS_VER3 && !force3) { retrycnt = orgcnt; nfsvers = NFS_VER2; mntvers = RPCMNT_VER1; nfsargsp->flags &= ~NFSMNT_NFSV3; goto tryagain; } else { warnx("%s", clnt_sperror(clp, "MNT RPC")); } } if ((opflags & ISBGRND) == 0) warnx("%s", clnt_sperror(clp, "bad MNT RPC")); } else { auth_destroy(clp->cl_auth); clnt_destroy(clp); retrycnt = 0; } } } if (--retrycnt > 0) { if (opflags & BGRND) { opflags &= ~BGRND; if ((i = fork())) { if (i == -1) err(1, "fork"); exit(0); } (void) setsid(); (void) close(STDIN_FILENO); (void) close(STDOUT_FILENO); (void) close(STDERR_FILENO); (void) chdir("/"); opflags |= ISBGRND; } sleep(60); } } if (nfhret.stat) { if (opflags & ISBGRND) exit(1); warnc(nfhret.stat, "can't access %s", spec); return (0); } saddr.sin_port = htons(tport); nfsargsp->addr = (struct sockaddr *) &saddr; nfsargsp->addrlen = sizeof (saddr); nfsargsp->fh = nfhret.nfh; nfsargsp->fhsize = nfhret.fhsize; nfsargsp->hostname = nam; return (1); }
int copy(char *argv[], enum op type, int fts_options) { struct stat to_stat; FTS *ftsp; FTSENT *curr; int base, nlen, rval; char *p, *target_mid; base = 0; if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) err(1, NULL); for (rval = 0; (curr = fts_read(ftsp)) != NULL;) { switch (curr->fts_info) { case FTS_NS: case FTS_DNR: case FTS_ERR: warnx("%s: %s", curr->fts_path, strerror(curr->fts_errno)); rval = 1; continue; case FTS_DC: warnx("%s: directory causes a cycle", curr->fts_path); rval = 1; continue; } /* * If we are in case (2) or (3) above, we need to append the * source name to the target name. */ if (type != FILE_TO_FILE) { /* * Need to remember the roots of traversals to create * correct pathnames. If there's a directory being * copied to a non-existent directory, e.g. * cp -R a/dir noexist * the resulting path name should be noexist/foo, not * noexist/dir/foo (where foo is a file in dir), which * is the case where the target exists. * * Also, check for "..". This is for correct path * concatenation for paths ending in "..", e.g. * cp -R .. /tmp * Paths ending in ".." are changed to ".". This is * tricky, but seems the easiest way to fix the problem. * * XXX * Since the first level MUST be FTS_ROOTLEVEL, base * is always initialized. */ if (curr->fts_level == FTS_ROOTLEVEL) { if (type != DIR_TO_DNE) { p = find_last_component(curr->fts_path); base = p - curr->fts_path; if (!strcmp(&curr->fts_path[base], "..")) base += 1; } else base = curr->fts_pathlen; } p = &curr->fts_path[base]; nlen = curr->fts_pathlen - base; target_mid = to.target_end; if (*p != '/' && target_mid[-1] != '/') *target_mid++ = '/'; *target_mid = '\0'; if (target_mid - to.p_path + nlen >= PATH_MAX) { warnx("%s%s: name too long (not copied)", to.p_path, p); rval = 1; continue; } (void)strncat(target_mid, p, nlen); to.p_end = target_mid + nlen; *to.p_end = '\0'; } /* Not an error but need to remember it happened */ if (stat(to.p_path, &to_stat) == -1) { if (curr->fts_info == FTS_DP) continue; /* * We use fts_pointer as a boolean to indicate that * we created this directory ourselves. We'll use * this later on via the fts_dne macro to decide * whether or not to set the directory mode during * the post-order pass. */ curr->fts_pointer = (void *)1; } else { /* * Set directory mode/user/times on the post-order * pass. We can't do this earlier because the mode * may not allow us write permission. Furthermore, * if we set the times during the pre-order pass, * they will get changed later when the directory * is populated. */ if (curr->fts_info == FTS_DP) { if (!S_ISDIR(to_stat.st_mode)) continue; /* * If not -p and directory didn't exist, set * it to be the same as the from directory, * unmodified by the umask; arguably wrong, * but it's been that way forever. */ if (pflag && setfile(curr->fts_statp, -1)) rval = 1; else if (fts_dne(curr)) (void)chmod(to.p_path, curr->fts_statp->st_mode); continue; } if (to_stat.st_dev == curr->fts_statp->st_dev && to_stat.st_ino == curr->fts_statp->st_ino) { warnx("%s and %s are identical (not copied).", to.p_path, curr->fts_path); rval = 1; if (S_ISDIR(curr->fts_statp->st_mode)) (void)fts_set(ftsp, curr, FTS_SKIP); continue; } if (!S_ISDIR(curr->fts_statp->st_mode) && S_ISDIR(to_stat.st_mode)) { warnx("cannot overwrite directory %s with non-directory %s", to.p_path, curr->fts_path); rval = 1; continue; } } switch (curr->fts_statp->st_mode & S_IFMT) { case S_IFLNK: if (copy_link(curr, !fts_dne(curr))) rval = 1; break; case S_IFDIR: if (!Rflag && !rflag) { warnx("%s is a directory (not copied).", curr->fts_path); (void)fts_set(ftsp, curr, FTS_SKIP); rval = 1; break; } /* * If the directory doesn't exist, create the new * one with the from file mode plus owner RWX bits, * modified by the umask. Trade-off between being * able to write the directory (if from directory is * 555) and not causing a permissions race. If the * umask blocks owner writes, we fail.. */ if (fts_dne(curr)) { if (mkdir(to.p_path, curr->fts_statp->st_mode | S_IRWXU) < 0) err(1, "%s", to.p_path); } else if (!S_ISDIR(to_stat.st_mode)) errc(1, ENOTDIR, "%s", to.p_path); break; case S_IFBLK: case S_IFCHR: if (Rflag) { if (copy_special(curr->fts_statp, !fts_dne(curr))) rval = 1; } else if (copy_file(curr, fts_dne(curr))) rval = 1; break; case S_IFIFO: if (Rflag) { if (copy_fifo(curr->fts_statp, !fts_dne(curr))) rval = 1; } else if (copy_file(curr, fts_dne(curr))) rval = 1; break; case S_IFSOCK: warnc(EOPNOTSUPP, "%s", curr->fts_path); break; default: if (copy_file(curr, fts_dne(curr))) rval = 1; break; } } if (errno) err(1, "fts_read"); (void)fts_close(ftsp); return (rval); }
int main(int argc, char *argv[]) { char *domain, *p, *ttyn, *shell, *fullname, *instance; char *lipaddr, *script, *ripaddr, *style, *type, *fqdn; char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; char localhost[MAXHOSTNAMELEN], *copyright; char mail[sizeof(_PATH_MAILDIR) + 1 + NAME_MAX]; int ask, ch, cnt, fflag, pflag, quietlog, rootlogin, lastchance; int error, homeless, needto, authok, tries, backoff; struct addrinfo *ai, hints; struct rlimit cds, scds; quad_t expire, warning; struct utmp utmp; struct group *gr; struct stat st; uid_t uid; openlog("login", LOG_ODELAY, LOG_AUTH); fqdn = lipaddr = ripaddr = fullname = type = NULL; authok = 0; tries = 10; backoff = 3; domain = NULL; if (gethostname(localhost, sizeof(localhost)) < 0) { syslog(LOG_ERR, "couldn't get local hostname: %m"); strlcpy(localhost, "localhost", sizeof(localhost)); } else if ((domain = strchr(localhost, '.'))) { domain++; if (*domain && strchr(domain, '.') == NULL) domain = localhost; } if ((as = auth_open()) == NULL) { syslog(LOG_ERR, "auth_open: %m"); err(1, "unable to initialize BSD authentication"); } auth_setoption(as, "login", "yes"); /* * -p is used by getty to tell login not to destroy the environment * -f is used to skip a second login authentication * -h is used by other servers to pass the name of the remote * host to login so that it may be placed in utmp and wtmp */ fflag = pflag = 0; uid = getuid(); while ((ch = getopt(argc, argv, "fh:pu:L:R:")) != -1) switch (ch) { case 'f': fflag = 1; break; case 'h': if (uid) { warnc(EPERM, "-h option"); quickexit(1); } free(fqdn); if ((fqdn = strdup(optarg)) == NULL) { warn(NULL); quickexit(1); } auth_setoption(as, "fqdn", fqdn); if (domain && (p = strchr(optarg, '.')) && strcasecmp(p+1, domain) == 0) *p = 0; hostname = optarg; auth_setoption(as, "hostname", hostname); break; case 'L': if (uid) { warnc(EPERM, "-L option"); quickexit(1); } if (lipaddr) { warnx("duplicate -L option"); quickexit(1); } lipaddr = optarg; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_CANONNAME; error = getaddrinfo(lipaddr, NULL, &hints, &ai); if (!error) { strlcpy(localhost, ai->ai_canonname, sizeof(localhost)); freeaddrinfo(ai); } else strlcpy(localhost, lipaddr, sizeof(localhost)); auth_setoption(as, "local_addr", lipaddr); break; case 'p': pflag = 1; break; case 'R': if (uid) { warnc(EPERM, "-R option"); quickexit(1); } if (ripaddr) { warnx("duplicate -R option"); quickexit(1); } ripaddr = optarg; auth_setoption(as, "remote_addr", ripaddr); break; case 'u': if (uid) { warnc(EPERM, "-u option"); quickexit(1); } rusername = optarg; break; default: if (!uid) syslog(LOG_ERR, "invalid flag %c", ch); (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [-L local-addr] " "[-R remote-addr] [-u username]\n\t[user]\n"); quickexit(1); } argc -= optind; argv += optind; if (*argv) { username = *argv; ask = 0; } else ask = 1; /* * If effective user is not root, just run su(1) to emulate login(1). */ if (geteuid() != 0) { char *av[5], **ap; auth_close(as); closelog(); closefrom(STDERR_FILENO + 1); ap = av; *ap++ = _PATH_SU; *ap++ = "-L"; if (!pflag) *ap++ = "-l"; if (!ask) *ap++ = username; *ap = NULL; execv(_PATH_SU, av); warn("unable to exec %s", _PATH_SU); _exit(1); } ttyn = ttyname(STDIN_FILENO); if (ttyn == NULL || *ttyn == '\0') { (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); ttyn = tname; } if ((tty = strrchr(ttyn, '/'))) ++tty; else tty = ttyn; /* * Since login deals with sensitive information, turn off coredumps. */ if (getrlimit(RLIMIT_CORE, &scds) < 0) { syslog(LOG_ERR, "couldn't get core dump size: %m"); scds.rlim_cur = scds.rlim_max = QUAD_MIN; } cds.rlim_cur = cds.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &cds) < 0) { syslog(LOG_ERR, "couldn't set core dump size to 0: %m"); scds.rlim_cur = scds.rlim_max = QUAD_MIN; } (void)signal(SIGALRM, timedout); if (argc > 1) { needto = 0; (void)alarm(timeout); } else needto = 1; (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)signal(SIGHUP, SIG_IGN); (void)setpriority(PRIO_PROCESS, 0, 0); #ifdef notyet /* XXX - we don't (yet) support per-tty auth stuff */ /* BSDi uses a ttys.conf file but we could just overload /etc/ttys */ /* * Classify the attempt. * By default we use the value in the ttys file. * If there is a classify script we run that as * * classify [-f] [username] */ if (type = getttyauth(tty)) auth_setoption(as, "auth_type", type); #endif /* get the default login class */ if ((lc = login_getclass(0)) == NULL) { /* get the default class */ warnx("Failure to retrieve default class"); quickexit(1); } timeout = (u_int)login_getcapnum(lc, "login-timeout", 300, 300); if ((script = login_getcapstr(lc, "classify", NULL, NULL)) != NULL) { unsetenv("AUTH_TYPE"); unsetenv("REMOTE_NAME"); if (script[0] != '/') { syslog(LOG_ERR, "Invalid classify script: %s", script); warnx("Classification failure"); quickexit(1); } shell = strrchr(script, '/') + 1; auth_setstate(as, AUTH_OKAY); auth_call(as, script, shell, fflag ? "-f" : username, fflag ? username : 0, (char *)0); if (!(auth_getstate(as) & AUTH_ALLOW)) quickexit(1); auth_setenv(as); if ((p = getenv("AUTH_TYPE")) != NULL && strncmp(p, "auth-", 5) == 0) type = p; if ((p = getenv("REMOTE_NAME")) != NULL) hostname = p; /* * we may have changed some values, reset them */ auth_clroptions(as); if (type) auth_setoption(as, "auth_type", type); if (fqdn) auth_setoption(as, "fqdn", fqdn); if (hostname) auth_setoption(as, "hostname", hostname); if (lipaddr) auth_setoption(as, "local_addr", lipaddr); if (ripaddr) auth_setoption(as, "remote_addr", ripaddr); } /* * Request the things like the approval script print things * to stdout (in particular, the nologins files) */ auth_setitem(as, AUTHV_INTERACTIVE, "True"); for (cnt = 0;; ask = 1) { /* * Clean up our current authentication session. * Options are not cleared so we need to clear any * we might set below. */ auth_clean(as); auth_clroption(as, "style"); auth_clroption(as, "lastchance"); lastchance = 0; if (ask) { fflag = 0; getloginname(); } if (needto) { needto = 0; alarm(timeout); } if ((style = strchr(username, ':')) != NULL) *style++ = '\0'; if (fullname) free(fullname); if (auth_setitem(as, AUTHV_NAME, username) < 0 || (fullname = strdup(username)) == NULL) { syslog(LOG_ERR, "%m"); warn(NULL); quickexit(1); } rootlogin = 0; if ((instance = strchr(username, '/')) != NULL) { if (strncmp(instance + 1, "root", 4) == 0) rootlogin = 1; *instance++ = '\0'; } else instance = ""; if (strlen(username) > UT_NAMESIZE) username[UT_NAMESIZE] = '\0'; /* * Note if trying multiple user names; log failures for * previous user name, but don't bother logging one failure * for nonexistent name (mistyped username). */ if (failures && strcmp(tbuf, username)) { if (failures > (pwd ? 0 : 1)) badlogin(tbuf); failures = 0; } (void)strlcpy(tbuf, username, sizeof(tbuf)); if ((pwd = getpwnam(username)) != NULL && auth_setpwd(as, pwd) < 0) { syslog(LOG_ERR, "%m"); warn(NULL); quickexit(1); } lc = login_getclass(pwd ? pwd->pw_class : NULL); if (!lc) goto failed; style = login_getstyle(lc, style, type); if (!style) goto failed; /* * We allow "login-tries" attempts to login but start * slowing down after "login-backoff" attempts. */ tries = (int)login_getcapnum(lc, "login-tries", 10, 10); backoff = (int)login_getcapnum(lc, "login-backoff", 3, 3); /* * Turn off the fflag if we have an invalid user * or we are not root and we are trying to change uids. */ if (!pwd || (uid && uid != pwd->pw_uid)) fflag = 0; if (pwd && pwd->pw_uid == 0) rootlogin = 1; /* * If we do not have the force flag authenticate the user */ if (!fflag) { lastchance = login_getcaptime(lc, "password-dead", 0, 0) != 0; if (lastchance) auth_setoption(as, "lastchance", "yes"); /* * Once we start asking for a password * we want to log a failure on a hup. */ signal(SIGHUP, sighup); auth_verify(as, style, NULL, lc->lc_class, NULL); authok = auth_getstate(as); /* * If their password expired and it has not been * too long since then, give the user one last * chance to change their password */ if ((authok & AUTH_PWEXPIRED) && lastchance) { authok = AUTH_OKAY; } else lastchance = 0; if ((authok & AUTH_ALLOW) == 0) goto failed; if (auth_setoption(as, "style", style) < 0) { syslog(LOG_ERR, "%m"); warn(NULL); quickexit(1); } } /* * explicitly reject users without password file entries */ if (pwd == NULL) goto failed; /* * If trying to log in as root on an insecure terminal, * refuse the login attempt unless the authentication * style explicitly says a root login is okay. */ if (pwd && rootlogin && !rootterm(tty)) goto failed; if (fflag) { type = 0; style = "forced"; } break; failed: if (authok & AUTH_SILENT) quickexit(0); if (rootlogin && !rootterm(tty)) { warnx("%s login refused on this terminal.", fullname); if (hostname) syslog(LOG_NOTICE, "LOGIN %s REFUSED FROM %s%s%s ON TTY %s", fullname, rusername ? rusername : "", rusername ? "@" : "", hostname, tty); else syslog(LOG_NOTICE, "LOGIN %s REFUSED ON TTY %s", fullname, tty); } else { if (!as || (p = auth_getvalue(as, "errormsg")) == NULL) p = "Login incorrect"; (void)printf("%s\n", p); } failures++; if (pwd) log_failedlogin(pwd->pw_uid, hostname, rusername, tty); /* * By default, we allow 10 tries, but after 3 we start * backing off to slow down password guessers. */ if (++cnt > backoff) { if (cnt >= tries) { badlogin(username); sleepexit(1); } sleep((u_int)((cnt - backoff) * tries / 2)); } } /* committed to login -- turn off timeout */ (void)alarm(0); endpwent(); shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell); if (*shell == '\0') shell = _PATH_BSHELL; else if (strlen(shell) >= MAXPATHLEN) { syslog(LOG_ERR, "shell path too long: %s", shell); warnx("invalid shell"); quickexit(1); } /* Destroy environment unless user has requested its preservation. */ if (!pflag) { if ((environ = calloc(1, sizeof (char *))) == NULL) err(1, "calloc"); } else { char **cpp, **cpp2; for (cpp2 = cpp = environ; *cpp; cpp++) { if (strncmp(*cpp, "LD_", 3) && strncmp(*cpp, "ENV=", 4) && strncmp(*cpp, "BASH_ENV=", 9) && strncmp(*cpp, "IFS=", 4)) *cpp2++ = *cpp; } *cpp2 = 0; } /* Note: setusercontext(3) will set PATH */ if (setenv("HOME", pwd->pw_dir, 1) == -1 || setenv("SHELL", pwd->pw_shell, 1) == -1) { warn("unable to setenv()"); quickexit(1); } if (term[0] == '\0') (void)strlcpy(term, stypeof(tty), sizeof(term)); (void)snprintf(mail, sizeof(mail), "%s/%s", _PATH_MAILDIR, pwd->pw_name); if (setenv("TERM", term, 0) == -1 || setenv("LOGNAME", pwd->pw_name, 1) == -1 || setenv("USER", pwd->pw_name, 1) == -1 || setenv("MAIL", mail, 1) == -1) { warn("unable to setenv()"); quickexit(1); } if (hostname) { if (setenv("REMOTEHOST", hostname, 1) == -1) { warn("unable to setenv()"); quickexit(1); } } if (rusername) { if (setenv("REMOTEUSER", rusername, 1) == -1) { warn("unable to setenv()"); quickexit(1); } } if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH)) { warn("unable to set user context"); quickexit(1); } auth_setenv(as); /* if user not super-user, check for disabled logins */ if (!rootlogin) auth_checknologin(lc); setegid(pwd->pw_gid); seteuid(pwd->pw_uid); homeless = chdir(pwd->pw_dir); if (homeless) { if (login_getcapbool(lc, "requirehome", 0)) { (void)printf("No home directory %s!\n", pwd->pw_dir); quickexit(1); } if (chdir("/")) quickexit(0); } quietlog = ((strcmp(pwd->pw_shell, "/sbin/nologin") == 0) || login_getcapbool(lc, "hushlogin", 0) || (access(_PATH_HUSHLOGIN, F_OK) == 0)); seteuid(0); setegid(0); /* XXX use a saved gid instead? */ if ((p = auth_getvalue(as, "warnmsg")) != NULL) (void)printf("WARNING: %s\n\n", p); expire = auth_check_expire(as); if (expire < 0) { (void)printf("Sorry -- your account has expired.\n"); quickexit(1); } else if (expire > 0 && !quietlog) { warning = login_getcaptime(lc, "expire-warn", 2 * DAYSPERWEEK * SECSPERDAY, 2 * DAYSPERWEEK * SECSPERDAY); if (expire < warning) (void)printf("Warning: your account expires on %s", ctime(&pwd->pw_expire)); } /* Nothing else left to fail -- really log in. */ (void)signal(SIGHUP, SIG_DFL); memset(&utmp, 0, sizeof(utmp)); (void)time(&utmp.ut_time); (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); if (hostname) (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); login(&utmp); if (!quietlog) (void)check_failedlogin(pwd->pw_uid); dolastlog(quietlog); login_fbtab(tty, pwd->pw_uid, pwd->pw_gid); (void)chown(ttyn, pwd->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); /* If fflag is on, assume caller/authenticator has logged root login. */ if (rootlogin && fflag == 0) { if (hostname) syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s%s%s", username, tty, rusername ? rusername : "", rusername ? "@" : "", hostname); else syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); } if (!quietlog) { if ((copyright = login_getcapstr(lc, "copyright", NULL, NULL)) != NULL) auth_cat(copyright); motd(); if (stat(mail, &st) == 0 && st.st_size != 0) (void)printf("You have %smail.\n", (st.st_mtime > st.st_atime) ? "new " : ""); } (void)signal(SIGALRM, SIG_DFL); (void)signal(SIGQUIT, SIG_DFL); (void)signal(SIGHUP, SIG_DFL); (void)signal(SIGINT, SIG_DFL); (void)signal(SIGTSTP, SIG_IGN); tbuf[0] = '-'; (void)strlcpy(tbuf + 1, (p = strrchr(shell, '/')) ? p + 1 : shell, sizeof(tbuf) - 1); if ((scds.rlim_cur != QUAD_MIN || scds.rlim_max != QUAD_MIN) && setrlimit(RLIMIT_CORE, &scds) < 0) syslog(LOG_ERR, "couldn't reset core dump size: %m"); if (lastchance) (void)printf("WARNING: Your password has expired." " You must change your password, now!\n"); if (setusercontext(lc, pwd, rootlogin ? 0 : pwd->pw_uid, LOGIN_SETALL & ~LOGIN_SETPATH) < 0) { warn("unable to set user context"); quickexit(1); } if (homeless) { (void)printf("No home directory %s!\n", pwd->pw_dir); (void)printf("Logging in with home = \"/\".\n"); (void)setenv("HOME", "/", 1); } if (auth_approval(as, lc, NULL, "login") == 0) { if (auth_getstate(as) & AUTH_EXPIRED) (void)printf("Sorry -- your account has expired.\n"); else (void)printf("approval failure\n"); quickexit(1); } /* * The last thing we do is discard all of the open file descriptors. * Last because the C library may have some open. */ closefrom(STDERR_FILENO + 1); /* * Close the authentication session, make sure it is marked * as okay so no files are removed. */ auth_setstate(as, AUTH_OKAY); auth_close(as); execlp(shell, tbuf, (char *)NULL); err(1, "%s", shell); }
int main(int argc, char *argv[]) { int ch, exitval, success, pflag; mode_t omode, *set = (mode_t *)NULL; char *mode; pflag = 0; mode = NULL; while ((ch = getopt(argc, argv, "m:pv")) != -1) switch(ch) { case 'm': mode = optarg; break; case 'p': pflag = 1; break; case 'v': vflag = 1; break; case '?': default: usage(); } // argc -= optind; argv += optind; if (argv[0] == NULL) usage(); if (mode == NULL) { omode = S_IRWXU | S_IRWXG | S_IRWXO; } else { if ((set = setmode(mode)) == NULL) errx(1, "invalid file mode: %s", mode); omode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO); free(set); } for (exitval = 0; *argv != NULL; ++argv) { success = 1; if (pflag) { int status = mkpath_np(*argv, omode); if (status && status != EEXIST) { warnc(status, "%s", *argv); success = 0; } } else if (mkdir(*argv, omode) < 0) { if (errno == ENOTDIR || errno == ENOENT) warn("%s", dirname(*argv)); else warn("%s", *argv); success = 0; } else if (vflag) (void)printf("mkdir: created directory '%s'\n", *argv); if (!success) exitval = 1; /* * The mkdir() and umask() calls both honor only the low * nine bits, so if you try to set a mode including the * sticky, setuid, setgid bits you lose them. Don't do * this unless the user has specifically requested a mode, * as chmod will (obviously) ignore the umask. */ if (success && mode != NULL && chmod(*argv, omode) == -1) { warn("%s", *argv); exitval = 1; } } exit(exitval); }
int main(int argc, char **argv) { gid_t gid; addr_t addr; struct sigaction sa; int c, dFlag, vFlag; unsigned long max_message_size; const char *queuename, *tablename; ctxt = NULL; gid = (gid_t) -1; vFlag = dFlag = 0; tablename = queuename = NULL; if (NULL == (queue = queue_init())) { errx("queue_init failed"); // TODO: better } atexit(cleanup); sa.sa_handler = &on_signal; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sa.sa_flags = SA_RESTART; sigaction(SIGUSR1, &sa, NULL); if (NULL == (engine = get_default_engine())) { errx("no engine available for your system"); } while (-1 != (c = getopt_long(argc, argv, optstr, long_options, NULL))) { switch (c) { case 'b': { unsigned long val; if (parse_ulong(optarg, &val)) { queue_set_attribute(queue, QUEUE_ATTR_MAX_MESSAGE_SIZE, val); // TODO: check returned value } break; } case 'd': dFlag = 1; break; case 'e': { if (NULL == (engine = get_engine_by_name(optarg))) { errx("unknown engine '%s'", optarg); } break; } case 'g': { struct group *grp; if (NULL == (grp = getgrnam(optarg))) { errc("getgrnam failed"); } gid = grp->gr_gid; break; } case 'l': { logfilename = optarg; if (NULL == (err_file = fopen(logfilename, "a"))) { err_file = NULL; warnc("fopen '%s' failed, falling back to stderr", logfilename); } break; } case 'p': pidfilename = optarg; break; case 'q': queuename = optarg; break; case 's': { unsigned long val; if (parse_ulong(optarg, &val)) { queue_set_attribute(queue, QUEUE_ATTR_MAX_MESSAGE_IN_QUEUE, val); // TODO: check returned value } break; } case 't': tablename = optarg; break; case 'v': vFlag++; break; case 'h': default: usage(); } } argc -= optind; argv += optind; if (0 != argc || NULL == queuename || NULL == tablename) { usage(); } if (dFlag) { if (0 != daemon(0, !vFlag)) { errc("daemon failed"); } } if (NULL != pidfilename) { FILE *fp; if (NULL == (fp = fopen(pidfilename, "w"))) { warnc("can't create pid file '%s'", pidfilename); } else { fprintf(fp, "%ld\n", (long) getpid()); fclose(fp); } } if (((gid_t) -1) != gid) { if (0 != setgid(gid)) { errc("setgid failed"); } if (0 != setgroups(1, &gid)) { errc("setgroups failed"); } } CAP_RIGHTS_LIMIT(STDOUT_FILENO, CAP_WRITE); CAP_RIGHTS_LIMIT(STDERR_FILENO, CAP_WRITE); if (NULL != err_file/* && fileno(err_file) > 2*/) { CAP_RIGHTS_LIMIT(fileno(err_file), CAP_WRITE); } if (QUEUE_ERR_OK != queue_open(queue, queuename, QUEUE_FL_OWNER)) { errx("queue_open failed"); // TODO: better } if (QUEUE_ERR_OK != queue_get_attribute(queue, QUEUE_ATTR_MAX_MESSAGE_SIZE, &max_message_size)) { errx("queue_get_attribute failed"); // TODO: better } if (NULL == (buffer = calloc(++max_message_size, sizeof(*buffer)))) { errx("calloc failed"); } if (NULL != engine->open) { ctxt = engine->open(tablename); } if (0 == getuid() && engine->drop_privileges) { struct passwd *pwd; if (NULL == (pwd = getpwnam("nobody"))) { if (NULL == (pwd = getpwnam("daemon"))) { errx("no nobody or daemon user accounts found on this system"); } } if (0 != setuid(pwd->pw_uid)) { errc("setuid failed"); } } CAP_ENTER(); while (1) { ssize_t read; if (-1 == (read = queue_receive(queue, buffer, max_message_size))) { errc("queue_receive failed"); // TODO: better } else { if (!parse_addr(buffer, &addr)) { errx("parsing of '%s' failed", buffer); // TODO: better } else { engine->handle(ctxt, tablename, addr); } } } /* not reached */ return BANIPD_EXIT_SUCCESS; }