struct disklabel * getdiskbyname(const char *name) { static struct disklabel disk; struct disklabel *dp = &disk; struct partition *pp; char *buf; char *db_array[2] = { _PATH_DISKTAB, 0 }; char *cp, *cq; /* can't be register */ char p, max, psize[3], pbsize[3], pfsize[3], poffset[3], ptype[3]; u_int32_t *dx; if (cgetent(&buf, db_array, (char *) name) < 0) return NULL; bzero((char *)&disk, sizeof(disk)); /* * typename */ cq = dp->d_typename; cp = buf; while (cq < dp->d_typename + sizeof(dp->d_typename) - 1 && (*cq = *cp) && *cq != '|' && *cq != ':') cq++, cp++; *cq = '\0'; if (cgetstr(buf, "ty", &cq) > 0) { if (strcmp(cq, "removable") == 0) dp->d_flags |= D_REMOVABLE; else if (cq && strcmp(cq, "simulated") == 0) dp->d_flags |= D_RAMDISK; free(cq); } if (cgetcap(buf, "sf", ':') != NULL) dp->d_flags |= D_BADSECT; #define getnumdflt(field, dname, dflt) \ { long f; (field) = (cgetnum(buf, dname, &f) == -1) ? (dflt) : f; } getnumdflt(dp->d_secsize, "se", DEV_BSIZE); getnumdflt(dp->d_ntracks, "nt", 0); getnumdflt(dp->d_nsectors, "ns", 0); getnumdflt(dp->d_ncylinders, "nc", 0); if (cgetstr(buf, "dt", &cq) > 0) { dp->d_type = gettype(cq, dktypenames); free(cq); } else getnumdflt(dp->d_type, "dt", 0); getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks); getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders); getnumdflt(dp->d_rpm, "rm", 3600); getnumdflt(dp->d_interleave, "il", 1); getnumdflt(dp->d_trackskew, "sk", 0); getnumdflt(dp->d_cylskew, "cs", 0); getnumdflt(dp->d_headswitch, "hs", 0); getnumdflt(dp->d_trkseek, "ts", 0); getnumdflt(dp->d_bbsize, "bs", BBSIZE); getnumdflt(dp->d_sbsize, "sb", 0); strcpy(psize, "px"); strcpy(pbsize, "bx"); strcpy(pfsize, "fx"); strcpy(poffset, "ox"); strcpy(ptype, "tx"); max = 'a' - 1; pp = &dp->d_partitions[0]; for (p = 'a'; p < 'a' + MAXPARTITIONS; p++, pp++) { long l; psize[1] = pbsize[1] = pfsize[1] = poffset[1] = ptype[1] = p; if (cgetnum(buf, psize, &l) == -1) pp->p_size = 0; else { pp->p_size = l; cgetnum(buf, poffset, &l); pp->p_offset = l; getnumdflt(pp->p_fsize, pfsize, 0); if (pp->p_fsize) { long bsize; if (cgetnum(buf, pbsize, &bsize) == 0) pp->p_frag = bsize / pp->p_fsize; else pp->p_frag = 8; } getnumdflt(pp->p_fstype, ptype, 0); if (pp->p_fstype == 0) if (cgetstr(buf, ptype, &cq) >= 0) { pp->p_fstype = gettype(cq, fstypenames); free(cq); } max = p; } } dp->d_npartitions = max + 1 - 'a'; (void)strcpy(psize, "dx"); dx = dp->d_drivedata; for (p = '0'; p < '0' + NDDATA; p++, dx++) { psize[1] = p; getnumdflt(*dx, psize, 0); } dp->d_magic = DISKMAGIC; dp->d_magic2 = DISKMAGIC; free(buf); return (dp); }
/* * Cgetustr retrieves the value of the string capability cap from the * capability record pointed to by buf. The difference between cgetustr() * and cgetstr() is that cgetustr does not decode escapes but rather treats * all characters literally. A pointer to a NUL terminated malloc'd * copy of the string is returned in the char pointed to by str. The * length of the string not including the trailing NUL is returned on success, * -1 if the requested string capability couldn't be found, -2 if a system * error was encountered (storage allocation failure). */ ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetustr(char *buf, const char *cap, char **str) { u_int m_room; const char *bp; char *mp; int len; char *mem; /* * Find string capability cap */ if ((bp = cgetcap(buf, cap, '=')) == NULL) return (-1); /* * Conversion / storage allocation loop ... Allocate memory in * chunks SFRAG in size. */ if ((mem = malloc(SFRAG)) == NULL) { errno = ENOMEM; return (-2); /* couldn't even allocate the first fragment */ } m_room = SFRAG; mp = mem; while (*bp != ':' && *bp != '\0') { /* * Loop invariants: * There is always room for one more character in mem. * Mp always points just past last character in mem. * Bp always points at next character in buf. */ *mp++ = *bp++; m_room--; /* * Enforce loop invariant: if no room left in current * buffer, try to get some more. */ if (m_room == 0) { size_t size = mp - mem; if ((mem = realloc(mem, size + SFRAG)) == NULL) return (-2); m_room = SFRAG; mp = mem + size; } } *mp++ = '\0'; /* loop invariant let's us do this */ m_room--; len = mp - mem - 1; /* * Give back any extra memory and return value and success. */ if (m_room != 0) if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL) return (-2); *str = mem; return (len); }
/* * Cgetstr retrieves the value of the string capability cap from the * capability record pointed to by buf. A pointer to a decoded, NUL * terminated, malloc'd copy of the string is returned in the char * * pointed to by str. The length of the string not including the trailing * NUL is returned on success, -1 if the requested string capability * couldn't be found, -2 if a system error was encountered (storage * allocation failure). */ ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetstr(char *buf, const char *cap, char **str) { u_int m_room; const char *bp; char *mp; int len; char *mem, *nmem; *str = NULL; /* * Find string capability cap */ bp = cgetcap(buf, cap, '='); if (bp == NULL) return (-1); /* * Conversion / storage allocation loop ... Allocate memory in * chunks SFRAG in size. */ if ((mem = malloc(SFRAG)) == NULL) { errno = ENOMEM; return (-2); /* couldn't even allocate the first fragment */ } m_room = SFRAG; mp = mem; while (*bp != ':' && *bp != '\0') { /* * Loop invariants: * There is always room for one more character in mem. * Mp always points just past last character in mem. * Bp always points at next character in buf. */ if (*bp == '^') { bp++; if (*bp == ':' || *bp == '\0') break; /* drop unfinished escape */ *mp++ = *bp++ & 037; } else if (*bp == '\\') { bp++; if (*bp == ':' || *bp == '\0') break; /* drop unfinished escape */ if ('0' <= *bp && *bp <= '7') { int n, i; n = 0; i = 3; /* maximum of three octal digits */ do { n = n * 8 + (*bp++ - '0'); } while (--i && '0' <= *bp && *bp <= '7'); *mp++ = n; } else switch (*bp++) { case 'b': case 'B': *mp++ = '\b'; break; case 't': case 'T': *mp++ = '\t'; break; case 'n': case 'N': *mp++ = '\n'; break; case 'f': case 'F': *mp++ = '\f'; break; case 'r': case 'R': *mp++ = '\r'; break; case 'e': case 'E': *mp++ = ESC; break; case 'c': case 'C': *mp++ = ':'; break; default: /* * Catches '\', '^', and * everything else. */ *mp++ = *(bp-1); break; } } else *mp++ = *bp++; m_room--; /* * Enforce loop invariant: if no room left in current * buffer, try to get some more. */ if (m_room == 0) { size_t size = mp - mem; if ((nmem = realloc(mem, size + SFRAG)) == NULL) { free(mem); return (-2); } mem = nmem; m_room = SFRAG; mp = mem + size; } } *mp++ = '\0'; /* loop invariant let's us do this */ m_room--; len = mp - mem - 1; /* * Give back any extra memory and return value and success. */ if (m_room != 0) { if ((nmem = realloc(mem, (size_t)(mp - mem))) == NULL) { free(mem); return (-2); } mem = nmem; } *str = mem; return (len); }
/* * Getent implements the functions of cgetent. If fd is non-negative, * *db_array has already been opened and fd is the open file descriptor. We * do this to save time and avoid using up file descriptors for tc= * recursions. * * Getent returns the same success/failure codes as cgetent. On success, a * pointer to a malloc'ed capability record with all tc= capabilities fully * expanded and its length (not including trailing ASCII NUL) are left in * *cap and *len. * * Basic algorithm: * + Allocate memory incrementally as needed in chunks of size BFRAG * for capability buffer. * + Recurse for each tc=name and interpolate result. Stop when all * names interpolated, a name can't be found, or depth exceeds * MAX_RECURSION. */ static int getent(char **cap, size_t *len, char **db_array, int fd, const char *name, int depth, char *nfield) { char *r_end, *rp = NULL, **db_p; /* pacify gcc */ int myfd = 0, eof, foundit; char *record; int tc_not_resolved; /* * Return with ``loop detected'' error if we've recursed more than * MAX_RECURSION times. */ if (depth > MAX_RECURSION) return (-3); /* * Check if we have a top record from cgetset(). */ if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { size_t len = topreclen + BFRAG; if ((record = malloc (len)) == NULL) { errno = ENOMEM; return (-2); } (void)strlcpy(record, toprec, len); db_p = db_array; rp = record + topreclen + 1; r_end = rp + BFRAG; goto tc_exp; } /* * Allocate first chunk of memory. */ if ((record = malloc(BFRAG)) == NULL) { errno = ENOMEM; return (-2); } r_end = record + BFRAG; foundit = 0; /* * Loop through database array until finding the record. */ for (db_p = db_array; *db_p != NULL; db_p++) { eof = 0; /* * Open database if not already open. */ if (fd >= 0) { (void)lseek(fd, (off_t)0, SEEK_SET); } else { #ifdef USE_DB char pbuf[_POSIX_PATH_MAX]; char *cbuf; size_t clen; int retval; DB *capdbp; (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0)) != NULL) { free(record); retval = cdbget(capdbp, &record, name); if (retval < 0) { /* no record available */ (void)capdbp->close(capdbp); return (retval); } /* save the data; close frees it */ clen = strlen(record); cbuf = malloc(clen + 1); if (cbuf == NULL) return (-2); memmove(cbuf, record, clen + 1); if (capdbp->close(capdbp) < 0) { free(cbuf); return (-2); } *len = clen; *cap = cbuf; return (retval); } else #endif { fd = open(*db_p, O_RDONLY, 0); if (fd < 0) { /* No error on unfound file. */ continue; } myfd = 1; } } /* * Find the requested capability record ... */ { char buf[BUFSIZ]; char *b_end, *bp, *cp; int c, slash; /* * Loop invariants: * There is always room for one more character in record. * R_end always points just past end of record. * Rp always points just past last character in record. * B_end always points just past last character in buf. * Bp always points at next character in buf. * Cp remembers where the last colon was. */ b_end = buf; bp = buf; cp = 0; slash = 0; for (;;) { /* * Read in a line implementing (\, newline) * line continuation. */ rp = record; for (;;) { if (bp >= b_end) { int n; n = read(fd, buf, sizeof(buf)); if (n <= 0) { if (myfd) (void)close(fd); if (n < 0) { free(record); return (-2); } else { fd = -1; eof = 1; break; } } b_end = buf+n; bp = buf; } c = *bp++; if (c == '\n') { if (slash) { slash = 0; rp--; continue; } else break; } if (slash) { slash = 0; cp = 0; } if (c == ':') { /* * If the field was `empty' (i.e. * contained only white space), back up * to the colon (eliminating the * field). */ if (cp) rp = cp; else cp = rp; } else if (c == '\\') { slash = 1; } else if (c != ' ' && c != '\t') { /* * Forget where the colon was, as this * is not an empty field. */ cp = 0; } *rp++ = c; /* * Enforce loop invariant: if no room * left in record buffer, try to get * some more. */ if (rp >= r_end) { u_int pos; size_t newsize; pos = rp - record; newsize = r_end - record + BFRAG; record = realloc(record, newsize); if (record == NULL) { errno = ENOMEM; if (myfd) (void)close(fd); return (-2); } r_end = record + newsize; rp = record + pos; } } /* Eliminate any white space after the last colon. */ if (cp) rp = cp + 1; /* Loop invariant lets us do this. */ *rp++ = '\0'; /* * If encountered eof check next file. */ if (eof) break; /* * Toss blank lines and comments. */ if (*record == '\0' || *record == '#') continue; /* * See if this is the record we want ... */ if (cgetmatch(record, name) == 0) { if (nfield == NULL || !nfcmp(nfield, record)) { foundit = 1; break; /* found it! */ } } } } if (foundit) break; } if (!foundit) return (-1); /* * Got the capability record, but now we have to expand all tc=name * references in it ... */ tc_exp: { char *newicap, *s; size_t ilen, newilen; int diff, iret, tclen; char *icap, *scan, *tc, *tcstart, *tcend; /* * Loop invariants: * There is room for one more character in record. * R_end points just past end of record. * Rp points just past last character in record. * Scan points at remainder of record that needs to be * scanned for tc=name constructs. */ scan = record; tc_not_resolved = 0; for (;;) { if ((tc = cgetcap(scan, "tc", '=')) == NULL) break; /* * Find end of tc=name and stomp on the trailing `:' * (if present) so we can use it to call ourselves. */ s = tc; for (;;) if (*s == '\0') break; else if (*s++ == ':') { *(s - 1) = '\0'; break; } tcstart = tc - 3; tclen = s - tcstart; tcend = s; iret = getent(&icap, &ilen, db_p, fd, tc, depth+1, NULL); newicap = icap; /* Put into a register. */ newilen = ilen; if (iret != 0) { /* an error */ if (iret < -1) { if (myfd) (void)close(fd); free(record); return (iret); } if (iret == 1) tc_not_resolved = 1; /* couldn't resolve tc */ if (iret == -1) { *(s - 1) = ':'; scan = s - 1; tc_not_resolved = 1; continue; } } /* not interested in name field of tc'ed record */ s = newicap; for (;;) if (*s == '\0') break; else if (*s++ == ':') break; newilen -= s - newicap; newicap = s; /* make sure interpolated record is `:'-terminated */ s += newilen; if (*(s-1) != ':') { *s = ':'; /* overwrite NUL with : */ newilen++; } /* * Make sure there's enough room to insert the * new record. */ diff = newilen - tclen; if (diff >= r_end - rp) { u_int pos, tcpos, tcposend; size_t newsize; pos = rp - record; newsize = r_end - record + diff + BFRAG; tcpos = tcstart - record; tcposend = tcend - record; record = realloc(record, newsize); if (record == NULL) { errno = ENOMEM; if (myfd) (void)close(fd); free(icap); return (-2); } r_end = record + newsize; rp = record + pos; tcstart = record + tcpos; tcend = record + tcposend; } /* * Insert tc'ed record into our record. */ s = tcstart + newilen; memmove(s, tcend, (size_t)(rp - tcend)); memmove(tcstart, newicap, newilen); rp += diff; free(icap); /* * Start scan on `:' so next cgetcap works properly * (cgetcap always skips first field). */ scan = s-1; } } /* * Close file (if we opened it), give back any extra memory, and * return capability, length and success. */ if (myfd) (void)close(fd); *len = rp - record - 1; /* don't count NUL */ if (r_end > rp) if ((record = realloc(record, (size_t)(rp - record))) == NULL) { errno = ENOMEM; return (-2); } *cap = record; if (tc_not_resolved) return (1); return (0); }
int getlist(char ** db_array, char *name, struct blacklist *blist, struct blacklist *blistnew) { char *buf, *method, *file, *message; int fd, black = 0; size_t blc, bls; struct bl *bl = NULL; gzFile gzf; if (cgetent(&buf, db_array, name) != 0) err(1, "Can't find \"%s\" in spamd config", name); buf = fix_quoted_colons(buf); if (cgetcap(buf, "black", ':') != NULL) { /* use new list */ black = 1; blc = blistnew->blc; bls = blistnew->bls; bl = blistnew->bl; } else if (cgetcap(buf, "white", ':') != NULL) { /* apply to most recent blacklist */ black = 0; blc = blist->blc; bls = blist->bls; bl = blist->bl; } else errx(1, "Must have \"black\" or \"white\" in %s", name); switch (cgetstr(buf, "msg", &message)) { case -1: if (black) errx(1, "No msg for blacklist \"%s\"", name); break; case -2: errx(1, "malloc failed"); } switch (cgetstr(buf, "method", &method)) { case -1: method = NULL; break; case -2: errx(1, "malloc failed"); } switch (cgetstr(buf, "file", &file)) { case -1: errx(1, "No file given for %slist %s", black ? "black" : "white", name); case -2: errx(1, "malloc failed"); default: fd = open_file(method, file); if (fd == -1) err(1, "Can't open %s by %s method", file, method ? method : "file"); free(method); free(file); gzf = gzdopen(fd, "r"); if (gzf == NULL) errx(1, "gzdopen"); } free(buf); bl = add_blacklist(bl, &blc, &bls, gzf, !black); gzclose(gzf); if (bl == NULL) { warn("Could not add %slist %s", black ? "black" : "white", name); return (0); } if (black) { blistnew->message = message; blistnew->name = name; blistnew->black = black; blistnew->bl = bl; blistnew->blc = blc; blistnew->bls = bls; } else { /* whitelist applied to last active blacklist */ blist->bl = bl; blist->blc = blc; blist->bls = bls; } if (debug) fprintf(stderr, "%slist %s %zu entries\n", black ? "black" : "white", name, blc / 2); return (black); }
/* * Get a table entry. */ void gettable(const char *name, char *buf) { struct gettystrs *sp; struct gettynums *np; struct gettyflags *fp; long n; int l; char *p; char *msg = NULL; const char *dba[2]; static int firsttime = 1; dba[0] = _PATH_GETTYTAB; dba[1] = 0; if (firsttime) { /* * we need to strdup() anything in the strings array * initially in order to simplify things later */ for (sp = gettystrs; sp->field; sp++) if (sp->value != NULL) { /* handle these ones more carefully */ if (sp >= &gettystrs[4] && sp <= &gettystrs[6]) l = 2; else l = strlen(sp->value) + 1; if ((p = malloc(l)) != NULL) { strncpy(p, sp->value, l); p[l-1] = '\0'; } /* * replace, even if NULL, else we'll * have problems with free()ing static mem */ sp->value = p; } firsttime = 0; } switch (cgetent(&buf, (char **)dba, (char *)name)) { case 1: msg = "%s: couldn't resolve 'tc=' in gettytab '%s'"; case 0: break; case -1: msg = "%s: unknown gettytab entry '%s'"; break; case -2: msg = "%s: retrieving gettytab entry '%s': %m"; break; case -3: msg = "%s: recursive 'tc=' reference gettytab entry '%s'"; break; default: msg = "%s: unexpected cgetent() error for entry '%s'"; break; } if (msg != NULL) { syslog(LOG_ERR, msg, "getty", name); return; } for (sp = gettystrs; sp->field; sp++) { if ((l = cgetstr(buf, (char*)sp->field, &p)) >= 0) { if (sp->value) { /* prefer existing value */ if (strcmp(p, sp->value) != 0) free(sp->value); else { free(p); p = sp->value; } } sp->value = p; } else if (l == -1) { free(sp->value); sp->value = NULL; } } for (np = gettynums; np->field; np++) { if (cgetnum(buf, (char*)np->field, &n) == -1) np->set = 0; else { np->set = 1; np->value = n; } } for (fp = gettyflags; fp->field; fp++) { if (cgetcap(buf, (char *)fp->field, ':') == NULL) fp->set = 0; else { fp->set = 1; fp->value = 1 ^ fp->invrt; } } #ifdef DEBUG printf("name=\"%s\", buf=\"%s\"\r\n", name, buf); for (sp = gettystrs; sp->field; sp++) printf("cgetstr: %s=%s\r\n", sp->field, sp->value); for (np = gettynums; np->field; np++) printf("cgetnum: %s=%d\r\n", np->field, np->value); for (fp = gettyflags; fp->field; fp++) printf("cgetflags: %s='%c' set='%c'\r\n", fp->field, fp->value + '0', fp->set + '0'); #endif /* DEBUG */ }