/* * Get an entry for terminal name in buffer bp, * from the termcap file. Parse is very rudimentary; * we just notice escaped newlines. */ int tgetent(char *bp, char *name, int len) { char lbuf[BUFSIZ], *cp, *p; int rc1, rc2; trusted_device = 1; remotefile = cp = getenv(V_TERMCAP); if (cp == (char *)0 || strcmp(cp, SYSREMOTE) == 0) { remotefile = cp = SYSREMOTE; return (getent(bp, name, cp, len)); } else { if ((rc1 = getent(bp, name, cp, len)) != 1) *bp = '\0'; remotefile = cp = SYSREMOTE; rc2 = getent(lbuf, name, cp, sizeof (lbuf)); if (rc1 != 1 && rc2 != 1) return (rc2); if (rc2 == 1) { p = lbuf; if (rc1 == 1) while (*p++ != ':') ; if (strlen(bp) + strlen(p) >= len) { (void) write(2, "Remcap entry too long\n", 23); return (-1); } (void) strcat(bp, p); } tbuf = bp; return (1); } }
/* * Cgetent extracts the capability record name from the NULL terminated file * array db_array and returns a pointer to a malloc'd copy of it in buf. * Buf must be retained through all subsequent calls to cgetcap, cgetnum, * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, * -1 if the requested record couldn't be found, -2 if a system error was * encountered (couldn't open/read a file, etc.), and -3 if a potential * reference loop is detected. */ int cgetent(char **buf, char **db_array, const char *name) { u_int dummy; return (getent(buf, &dummy, db_array, NULL, name, 0, NULL)); }
/* * Cgetent extracts the capability record name from the NULL terminated file * array db_array and returns a pointer to a malloc'd copy of it in buf. * Buf must be retained through all subsequent calls to cgetcap, cgetnum, * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, * -1 if the requested record couldn't be found, -2 if a system error was * encountered (couldn't open/read a file, etc.), and -3 if a potential * reference loop is detected. */ ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL cgetent(char **buf, char **db_array, const char *name) { size_t dummy; return (getent(buf, &dummy, db_array, -1, name, 0, NULL)); }
/* * Get an entry for terminal name in buffer bp, * from the termcap file. Parse is very rudimentary; * we just notice escaped newlines. */ int tgetent(char *bp, char *name) { char *cp; remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF; return (getent(bp, name, cp)); }
/* * tnchktc: check the last entry, see if it's tc=xxx. If so, * recursively find xxx and append that entry (minus the names) * to take the place of the tc=xxx entry. This allows termcap * entries to say "like an HP2621 but doesn't turn on the labels". * Note that this works because of the left to right scan. */ int tnchktc(void) { char *p, *q; char tcname[64]; /* name of similar terminal */ char tcbuf[BUFSIZ]; char *holdtbuf = tbuf; int l; p = tbuf + strlen(tbuf) - 2; /* before the last colon */ while (*--p != ':') if (p < tbuf) { (void) write(2, "Bad remcap entry\n", 18); return (0); } p++; /* p now points to beginning of last field */ if (p[0] != 't' || p[1] != 'c') return (1); (void) strlcpy(tcname, p+3, sizeof (tcname)); q = tcname; while (*q && *q != ':') q++; *q = 0; if (++hopcount > MAXHOP) { (void) write(2, "Infinite tc= loop\n", 18); return (0); } if (getent(tcbuf, tcname, remotefile, sizeof (tcbuf)) != 1) { if (strcmp(remotefile, SYSREMOTE) == 0) return (0); else if (getent(tcbuf, tcname, SYSREMOTE, sizeof (tcbuf)) != 1) return (0); } for (q = tcbuf; *q++ != ':'; ) ; l = p - holdtbuf + strlen(q); if (l > BUFSIZ) { (void) write(2, "Remcap entry too long\n", 23); q[BUFSIZ - (p-holdtbuf)] = 0; } (void) strcpy(p, q); tbuf = holdtbuf; return (1); }
/* coverity[+alloc : arg-*0] */ int cgetent(char **buf, const char * const *db_array, const char *name) { size_t dummy; _DIAGASSERT(buf != NULL); _DIAGASSERT(db_array != NULL); _DIAGASSERT(name != NULL); return getent(buf, &dummy, db_array, -1, name, 0, NULL); }
/* * tnchktc: check the last entry, see if it's tc=xxx. If so, * recursively find xxx and append that entry (minus the names) * to take the place of the tc=xxx entry. This allows termcap * entries to say "like an HP2621 but doesn't turn on the labels". * Note that this works because of the left to right scan. */ int tnchktc(void) { char *p, *q; char tcname[16]; /* name of similar terminal */ char tcbuf[BUFSIZ]; char *holdtbuf = tbuf; int l; p = tbuf + strlen(tbuf) - 2; /* before the last colon */ while (*--p != ':') if (p < tbuf) { write(STDERR_FILENO, "Bad remcap entry\n", 18); return (0); } p++; /* p now points to beginning of last field */ if (p[0] != 't' || p[1] != 'c') return (1); strlcpy(tcname, p + 3, sizeof tcname); q = tcname; while (*q && *q != ':') q++; *q = 0; if (++hopcount > MAXHOP) { write(STDERR_FILENO, "Infinite tc= loop\n", 18); return (0); } if (getent(tcbuf, tcname, conffile) != 1) { return (0); } for (q = tcbuf; *q++ != ':'; ) ; l = p - holdtbuf + strlen(q); if (l > BUFSIZ) { write(STDERR_FILENO, "Remcap entry too long\n", 23); q[BUFSIZ - (p-holdtbuf)] = 0; } strcpy(p, q); tbuf = holdtbuf; return (1); }
/* * Cgetnext() gets either the first or next entry in the logical database * specified by db_array. It returns 0 upon completion of the database, 1 * upon returning an entry with more remaining, and -1 if an error occurs. */ int cgetnext(char **bp, char **db_array) { size_t len; int done, hadreaderr, savederrno, status; char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; u_int dummy; if (dbp == NULL) dbp = db_array; if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) { (void)cgetclose(); return (-1); } for (;;) { if (toprec && !gottoprec) { gottoprec = 1; line = toprec; } else { line = fgetln(pfp, &len); if (line == NULL && pfp) { hadreaderr = ferror(pfp); if (hadreaderr) savederrno = errno; fclose(pfp); pfp = NULL; if (hadreaderr) { cgetclose(); errno = savederrno; return (-1); } else { if (*++dbp == NULL) { (void)cgetclose(); return (0); } else if ((pfp = fopen(*dbp, "r")) == NULL) { (void)cgetclose(); return (-1); } else continue; } } else line[len - 1] = '\0'; if (len == 1) { slash = 0; continue; } if (isspace((unsigned char)*line) || *line == ':' || *line == '#' || slash) { if (line[len - 2] == '\\') slash = 1; else slash = 0; continue; } if (line[len - 2] == '\\') slash = 1; else slash = 0; } /* * Line points to a name line. */ done = 0; np = nbuf; for (;;) { for (cp = line; *cp != '\0'; cp++) { if (*cp == ':') { *np++ = ':'; done = 1; break; } if (*cp == '\\') break; *np++ = *cp; } if (done) { *np = '\0'; break; } else { /* name field extends beyond the line */ line = fgetln(pfp, &len); if (line == NULL && pfp) { /* Name extends beyond the EOF! */ hadreaderr = ferror(pfp); if (hadreaderr) savederrno = errno; fclose(pfp); pfp = NULL; if (hadreaderr) { cgetclose(); errno = savederrno; return (-1); } else { cgetclose(); return (-1); } } else line[len - 1] = '\0'; } } rp = buf; for(cp = nbuf; *cp != '\0'; cp++) if (*cp == '|' || *cp == ':') break; else *rp++ = *cp; *rp = '\0'; /* * XXX * Last argument of getent here should be nbuf if we want true * sequential access in the case of duplicates. * With NULL, getent will return the first entry found * rather than the duplicate entry record. This is a * matter of semantics that should be resolved. */ status = getent(bp, &dummy, db_array, -1, buf, 0, NULL); if (status == -2 || status == -3) (void)cgetclose(); return (status + 1); } /* NOTREACHED */ }
void domkdir (int argc, char **argv) { int n; firqb f; int newclu; char *p; word link, ulink, alink, qlink; uattr *u; ua_qt2 *q; if (argc == 0) { printf ("Usage: %s mkdir dir...\n", progname); return; } rmountrw (); if (sw.clusiz == NULL) { newclu = pcs; if (newclu > 16) newclu = 16; } else { newclu = strtol (sw.clusiz, &p, 10); if (newclu < 0) { newclu = -newclu; if (newclu < pcs) { newclu = pcs; if (newclu > 16) newclu = 16; } } if (*p != '\0' || (newclu < pcs && newclu < 16) || newclu > 16 || (newclu & (-newclu)) != newclu) { rumountrw (); /* dismount first */ printf ("Invalid clustersize %s\n", sw.clusiz); return; } } for (n = 0; n < argc; n++) { if (!parse (argv[n], &f) || f.flags != f_ppn) { printf ("Invalid PPN %s\n", argv[n]); continue; } if (initfilescan (&f, gfdatrtbl)) { printf ("Directory [%d,%d] already exists\n", f.cproj, f.cprog); } else { f.cproj = f.proj; /* set up for makedir */ f.cprog = f.prog; if (makedir (&f, newclu)) { if (sw.user != NULL) { fbread (curgfd + gfdatrtbl); link = fibufw[f.cprog]; readlktbl (link); alink = use(gfdne,k)->ulnk; if ((ulink = getent ()) == 0) printf ("No room to mark account as user account\n"); else { readlk (ulink); u = use(uattr,k); u->ulnk = alink; u->uatyp = aa_pas; MARKF; if ((qlink = getent ()) == 0) { printf ("No room for second quota block\n"); qlink = ulink; } else { readlk (qlink); q = use(ua_qt2,k); q->ulnk = ulink; q->uatyp = aa_qt2; q->a2_job = 255U; q->a2_rib = 4; q->a2_msg = 12; MARKF; } readlk (link); use(gfdne,k)->ulnk = qlink; MARKF; } } if (sw.verbose != NULL) printf ("Account [%d,%d] created\n", f.proj, f.prog); } } } rumountrw (); }
int tgetent( char *tbuf, /* Buffer to hold termcap entry, TBUFSZ bytes max */ char *term) /* Name of terminal */ { char tcbuf[32]; /* Temp buffer to handle */ char *tcptr = tcbuf; /* extended entries */ char *tcap = TERMCAPFILE; /* Default termcap file */ char *tmp; FILE *termcap; int retval = 0; int len; if ((tmp = (char *)mch_getenv((char_u *)"TERMCAP")) != NULL) { if (*tmp == '/') /* TERMCAP = name of termcap file */ { tcap = tmp ; #if defined(AMIGA) /* Convert /usr/share/lib/termcap to usr:share/lib/termcap */ tcap++; tmp = strchr(tcap, '/'); if (tmp) *tmp = ':'; #endif } else /* TERMCAP = termcap entry itself */ { int tlen = strlen(term); while (*tmp && *tmp != ':') /* Check if TERM matches */ { char *nexttmp; while (*tmp == '|') tmp++; nexttmp = _find(tmp, ":|"); /* Rhialto */ if (tmp+tlen == nexttmp && _match(tmp, term) == tlen) { strcpy(tbuf, tmp); tent = tbuf; return 1; } else tmp = nexttmp; } } } if (!(termcap = mch_fopen(tcap, "r"))) { strcpy(tbuf, tcap); return -1; } len = 0; while (getent(tbuf + len, term, termcap, TBUFSZ - len)) { tcptr = tcbuf; /* Rhialto */ if ((term = tgetstr("tc", &tcptr))) /* extended entry */ { rewind(termcap); len = strlen(tbuf); } else { retval = 1; tent = tbuf; /* reset it back to the beginning */ break; } } fclose(termcap); return retval; }
/*ARGSUSED*/ static void switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *dp, uint_t n_desc) { int iam; pid_t ent_pid = -1; nss_pheader_t *phdr = (nss_pheader_t *)((void *)argp); void *uptr; int len; size_t buflen; int callnum; char *me = "switcher"; _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_DEBUG) (me, "switcher ...\n"); if (argp == DOOR_UNREF_DATA) { (void) printf("Door Slam... exiting\n"); exit(0); } if (argp == NULL) { /* empty door call */ (void) door_return(NULL, 0, 0, 0); /* return the favor */ } /* * need to restart if main nscd and config file(s) changed */ if (_whoami == NSCD_MAIN) _nscd_restart_if_cfgfile_changed(); if ((phdr->nsc_callnumber & NSCDV2CATMASK) == NSCD_CALLCAT_APP) { /* make sure the packed buffer header is good */ if (validate_pheader(argp, arg_size, phdr->nsc_callnumber) == -1) (void) door_return(argp, arg_size, NULL, 0); switch (phdr->nsc_callnumber) { case NSCD_SEARCH: /* if a fallback to main nscd, skip per-user setup */ if (phdr->p_status != NSS_ALTRETRY) if_selfcred_return_per_user_door(argp, arg_size, dp, _whoami); lookup(argp, arg_size); break; case NSCD_SETENT: _nscd_APP_check_cred(argp, &ent_pid, "NSCD_SETENT", NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ALERT); if (NSCD_STATUS_IS_OK(phdr)) { if_selfcred_return_per_user_door(argp, arg_size, dp, _whoami); nss_psetent(argp, arg_size, ent_pid); } break; case NSCD_GETENT: getent(argp, arg_size); break; case NSCD_ENDENT: nss_pendent(argp, arg_size); break; case NSCD_PUT: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "door call NSCD_PUT not supported yet\n"); NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); break; case NSCD_GETHINTS: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "door call NSCD_GETHINTS not supported yet\n"); NSCD_SET_STATUS(phdr, NSS_ERROR, ENOTSUP); break; default: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "Unknown name service door call op %x\n", phdr->nsc_callnumber); NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); break; } (void) door_return(argp, arg_size, NULL, 0); } iam = NSCD_MAIN; callnum = phdr->nsc_callnumber & ~NSCD_WHOAMI; if (callnum == NSCD_IMHERE || callnum == NSCD_PULSE || callnum == NSCD_FORK) iam = phdr->nsc_callnumber & NSCD_WHOAMI; else callnum = phdr->nsc_callnumber; /* nscd -> nscd v2 calls */ /* make sure the buffer is good */ if (validate_N2Nbuf(argp, arg_size, callnum) == -1) (void) door_return(argp, arg_size, NULL, 0); switch (callnum) { case NSCD_PING: NSCD_SET_STATUS_SUCCESS(phdr); break; case NSCD_IMHERE: _nscd_proc_iamhere(argp, dp, n_desc, iam); break; case NSCD_PULSE: N2N_check_priv(argp, "NSCD_PULSE"); if (NSCD_STATUS_IS_OK(phdr)) _nscd_proc_pulse(argp, iam); break; case NSCD_FORK: N2N_check_priv(argp, "NSCD_FORK"); if (NSCD_STATUS_IS_OK(phdr)) _nscd_proc_fork(argp, iam); break; case NSCD_KILL: N2N_check_priv(argp, "NSCD_KILL"); if (NSCD_STATUS_IS_OK(phdr)) exit(0); break; case NSCD_REFRESH: N2N_check_priv(argp, "NSCD_REFRESH"); if (NSCD_STATUS_IS_OK(phdr)) { if (_nscd_refresh() != NSCD_SUCCESS) exit(1); NSCD_SET_STATUS_SUCCESS(phdr); } break; case NSCD_GETPUADMIN: if (_nscd_is_self_cred_on(0, NULL)) { _nscd_peruser_getadmin(argp, sizeof (nscd_admin_t)); } else { NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, NSCD_SELF_CRED_NOT_CONFIGURED); } break; case NSCD_GETADMIN: len = _nscd_door_getadmin((void *)argp); if (len == 0) break; /* size of door buffer not big enough, allocate one */ NSCD_ALLOC_DOORBUF(NSCD_GETADMIN, len, uptr, buflen); /* copy packed header */ *(nss_pheader_t *)uptr = *(nss_pheader_t *)((void *)argp); /* set new buffer size */ ((nss_pheader_t *)uptr)->pbufsiz = buflen; /* try one more time */ (void) _nscd_door_getadmin((void *)uptr); (void) door_return(uptr, buflen, NULL, 0); break; case NSCD_SETADMIN: N2N_check_priv(argp, "NSCD_SETADMIN"); if (NSCD_STATUS_IS_OK(phdr)) _nscd_door_setadmin(argp); break; case NSCD_KILLSERVER: N2N_check_priv(argp, "NSCD_KILLSERVER"); if (NSCD_STATUS_IS_OK(phdr)) { /* also kill the forker nscd if one is running */ _nscd_kill_forker(); exit(0); } break; default: _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR) (me, "Unknown name service door call op %d\n", phdr->nsc_callnumber); NSCD_SET_STATUS(phdr, NSS_ERROR, EINVAL); (void) door_return(argp, arg_size, NULL, 0); break; } (void) door_return(argp, arg_size, NULL, 0); }
/* * 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); }
void start_login(char *host, int autologin, char *name) { char **argv; #define TABBUFSIZ 512 char defent[TABBUFSIZ]; char defstrs[TABBUFSIZ]; #undef TABBUFSIZ const char *loginprog = NULL; extern struct sockaddr_storage from; char buf[sizeof(from) * 4 + 1]; scrub_env(); /* * -a : pass on the address of the host. * -h : pass on name of host. * WARNING: -h and -a are accepted by login * if and only if getuid() == 0. * -p : don't clobber the environment (so terminal type stays set). * * -f : force this login, he has already been authenticated */ argv = addarg(0, "login"); argv = addarg(argv, "-a"); (void)strvisx(buf, (const char *)(const void *)&from, sizeof(from), VIS_WHITE); argv = addarg(argv, buf); argv = addarg(argv, "-h"); argv = addarg(argv, host); argv = addarg(argv, "-p"); #ifdef LINEMODE /* * Set the environment variable "LINEMODE" to either * "real" or "kludge" if we are operating in either * real or kludge linemode. */ if (lmodetype == REAL_LINEMODE) setenv("LINEMODE", "real", 1); # ifdef KLUDGELINEMODE else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK) setenv("LINEMODE", "kludge", 1); # endif #endif #ifdef SECURELOGIN /* * don't worry about the -f that might get sent. * A -s is supposed to override it anyhow. */ if (require_secure_login) argv = addarg(argv, "-s"); #endif #ifdef AUTHENTICATION if (auth_level >= 0 && autologin == AUTH_VALID) { argv = addarg(argv, "-f"); argv = addarg(argv, "--"); argv = addarg(argv, name); } else #endif if (getenv("USER")) { argv = addarg(argv, "--"); argv = addarg(argv, getenv("USER")); /* * Assume that login will set the USER variable * correctly. For SysV systems, this means that * USER will no longer be set, just LOGNAME by * login. (The problem is that if the auto-login * fails, and the user then specifies a different * account name, he can get logged in with both * LOGNAME and USER in his environment, but the * USER value will be wrong. */ unsetenv("USER"); } if (getent(defent, gettyname) == 1) { char *cp = defstrs; loginprog = getstr("lo", &cp); } if (loginprog == NULL) loginprog = _PATH_LOGIN; closelog(); /* * This sleep(1) is in here so that telnetd can * finish up with the tty. There's a race condition * the login banner message gets lost... */ sleep(1); execv(loginprog, argv); syslog(LOG_ERR, "%s: %m", loginprog); fatalperror(net, loginprog); /*NOTREACHED*/ }
/* coverity[+alloc : arg-*0] */ int cgetnext(char **bp, const char * const *db_array) { size_t len = 0; int status, done; char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; size_t dummy; _DIAGASSERT(bp != NULL); _DIAGASSERT(db_array != NULL); if (dbp == NULL) dbp = db_array; if (pfp == NULL && (pfp = fopen(*dbp, "re")) == NULL) { (void)cgetclose(); return -1; } for (;;) { if (toprec != NULL && !gottoprec) { gottoprec = 1; line = toprec; } else { line = fgetln(pfp, &len); if (line == NULL) { if (pfp == NULL) return -1; if (ferror(pfp)) { (void)cgetclose(); return -1; } else { (void)fclose(pfp); pfp = NULL; if (*++dbp == NULL) { (void)cgetclose(); return 0; } else if ((pfp = fopen(*dbp, "re")) == NULL) { (void)cgetclose(); return -1; } else continue; } } else line[len - 1] = '\0'; if (len == 1) { slash = 0; continue; } if (isspace((unsigned char)*line) || *line == ':' || *line == '#' || slash) { if (line[len - 2] == '\\') slash = 1; else slash = 0; continue; } if (line[len - 2] == '\\') slash = 1; else slash = 0; } /* * Line points to a name line. */ if (len > sizeof(nbuf)) return -1; done = 0; np = nbuf; for (;;) { for (cp = line; *cp != '\0'; cp++) { if (*cp == ':') { *np++ = ':'; done = 1; break; } if (*cp == '\\') break; *np++ = *cp; } if (done) { *np = '\0'; break; } else { /* name field extends beyond the line */ line = fgetln(pfp, &len); if (line == NULL && pfp) { if (ferror(pfp)) { (void)cgetclose(); return -1; } (void)fclose(pfp); pfp = NULL; *np = '\0'; break; } else line[len - 1] = '\0'; } } if (len > sizeof(buf)) return -1; rp = buf; for (cp = nbuf; *cp != '\0'; cp++) if (*cp == '|' || *cp == ':') break; else *rp++ = *cp; *rp = '\0'; /* * XXX * Last argument of getent here should be nbuf if we want true * sequential access in the case of duplicates. * With NULL, getent will return the first entry found * rather than the duplicate entry record. This is a * matter of semantics that should be resolved. */ status = getent(bp, &dummy, db_array, -1, buf, 0, NULL); if (status == -2 || status == -3) (void)cgetclose(); return status + 1; } /* NOTREACHED */ }
/* * Getent implements the functions of cgetent. If fp is non-NULL, * *db_array has already been opened and fp 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, u_int *len, char **db_array, FILE *fp, const char *name, int depth, char *nfield) { DB *capdbp; char *r_end, *rp, **db_p; int myfd, eof, foundit, opened, retval, clen; char *record, *cbuf; int tc_not_resolved; char pbuf[PATH_MAX]; /* * Return with ``loop detected'' error if we've recursed more than * MAX_RECURSION times. */ if (depth > MAX_RECURSION) return (-3); opened = 0; /* * Check if we have a top record from cgetset(). */ if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { opened++; if ((record = malloc(topreclen + 1 + BFRAG)) == NULL) return (-2); memcpy(record, toprec, topreclen + 1); myfd = 0; 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) 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 (fp != NULL) { (void)fseek(fp, 0L, SEEK_SET); myfd = 0; opened++; } else { char *dbrecord; clen = snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); if (clen != -1 && clen < sizeof(pbuf) && usedb && (capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0))) { opened++; retval = cdbget(capdbp, &dbrecord, name); if (retval < 0) { /* no record available */ (void)capdbp->close(capdbp); continue; } free(record); /* save the data; close frees it */ clen = strlen(dbrecord); if ((cbuf = malloc(clen + 1)) == NULL) return (-2); memcpy(cbuf, dbrecord, clen + 1); if (capdbp->close(capdbp) < 0) { free(cbuf); return (-2); } /* assume tc='s have been expanded??? */ *len = clen; *cap = cbuf; return (retval); } else { fp = fopen(*db_p, "re"); if (fp == NULL) { /* No error on unfound file. */ continue; } myfd = 1; opened++; } } /* * Find the requested capability record ... */ { char buf[BUFSIZ]; char *b_end, *bp; int c; /* * 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. */ b_end = buf; bp = buf; for (;;) { /* * Read in a line implementing (\, newline) * line continuation. */ rp = record; for (;;) { if (bp >= b_end) { size_t n; n = fread(buf, 1, sizeof(buf), fp); if (n == 0) { eof = feof(fp); if (myfd) (void)fclose(fp); if (eof) { fp = NULL; break; } free(record); return (-2); } b_end = buf+n; bp = buf; } c = *bp++; if (c == '\n') { if (rp > record && *(rp-1) == '\\') { rp--; continue; } else break; } *rp++ = c; /* * Enforce loop invariant: if no room * left in record buffer, try to get * some more. */ if (rp >= r_end) { size_t pos; size_t newsize; char *nrecord; pos = rp - record; newsize = r_end - record + BFRAG; nrecord = realloc(record, newsize); if (nrecord == NULL) { free(record); if (myfd) (void)fclose(fp); errno = ENOMEM; return (-2); } record = nrecord; r_end = record + newsize; rp = record + pos; } } /* 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) { free(record); return (opened ? -1 : -2); } /* * Got the capability record, but now we have to expand all tc=name * references in it ... */ tc_exp: { char *s; u_int ilen; int diff, iret, tclen; char *ibuf, *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, fp, tc, depth+1, NULL); if (iret != 0) { /* an error */ if (iret < -1) { if (myfd) (void)fclose(fp); 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 = ibuf = icap; for (;;) if (*s == '\0') break; else if (*s++ == ':') break; ilen -= s - icap; icap = s; /* make sure interpolated record is `:'-terminated */ s += ilen; if (*(s-1) != ':') { *s = ':'; /* overwrite NUL with : */ ilen++; } /* * Make sure there's enough room to insert the * new record. */ diff = ilen - tclen; if (diff >= r_end - rp) { u_int pos, tcpos, tcposend; size_t newsize; char *nrecord; pos = rp - record; newsize = r_end - record + diff + BFRAG; tcpos = tcstart - record; tcposend = tcend - record; nrecord = realloc(record, newsize); if (nrecord == NULL) { free(record); if (myfd) (void)fclose(fp); free(ibuf); errno = ENOMEM; return (-2); } record = nrecord; r_end = record + newsize; rp = record + pos; tcstart = record + tcpos; tcend = record + tcposend; } /* * Insert tc'ed record into our record. */ s = tcstart + ilen; memmove(s, tcend, rp - tcend); memmove(tcstart, icap, ilen); rp += diff; free(ibuf); /* * 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)fclose(fp); *len = rp - record - 1; /* don't count NUL */ if (r_end > rp) { char *nrecord; if ((nrecord = realloc(record, rp - record)) == NULL) { free(record); errno = ENOMEM; return (-2); } record = nrecord; } *cap = record; if (tc_not_resolved) return (1); return (0); }
/* * Cgetnext() gets either the first or next entry in the logical database * specified by db_array. It returns 0 upon completion of the database, 1 * upon returning an entry with more remaining, and -1 if an error occurs. */ int cgetnext(char **cap, char **db_array) { size_t len, otopreclen = topreclen; int c, serrno, status = -1; char buf[BUFSIZ], nbuf[BSIZE]; char *b_end, *bp, *r_end, *rp; char *record = NULL; char *otoprec = toprec; u_int dummy; off_t pos; if (dbp == NULL) dbp = db_array; if (pfp == NULL && (pfp = fopen(*dbp, "re")) == NULL) goto done; /* * Check if we have an unused top record from cgetset(). */ if (toprec && !gottoprec) { gottoprec = 1; record = toprec; goto lookup; } /* * Allocate first chunk of memory. */ if ((record = malloc(BFRAG)) == NULL) goto done; r_end = record + BFRAG; /* * Find the next capability record */ /* * 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. */ b_end = buf; bp = buf; for (;;) { /* * Read in a line implementing (\, newline) * line continuation. */ rp = record; for (;;) { if (bp >= b_end) { size_t n; n = fread(buf, 1, sizeof(buf), pfp); if (n == 0) { if (ferror(pfp)) goto done; (void)fclose(pfp); pfp = NULL; if (*++dbp == NULL) { status = 0; goto done; } else if ((pfp = fopen(*dbp, "re")) == NULL) { goto done; } else continue; } b_end = buf + n; bp = buf; } c = *bp++; if (c == '\n') { if (rp > record && *(rp-1) == '\\') { rp--; continue; } else break; } *rp++ = c; /* * Enforce loop invariant: if no room * left in record buffer, try to get * some more. */ if (rp >= r_end) { size_t newsize, off; char *nrecord; off = rp - record; newsize = r_end - record + BFRAG; nrecord = realloc(record, newsize); if (nrecord == NULL) goto done; record = nrecord; r_end = record + newsize; rp = record + off; } } /* loop invariant lets us do this */ *rp++ = '\0'; /* * If not blank or comment, set toprec and topreclen so * getent() doesn't have to re-parse the file to find it. */ if (*record != '\0' && *record != '#') { /* Rewind to end of record */ fseeko(pfp, bp - b_end, SEEK_CUR); toprec = record; topreclen = rp - record; break; } } lookup: /* extract name from record */ len = strcspn(record, "|:"); memcpy(nbuf, record, len); nbuf[len] = '\0'; /* return value of getent() is one less than cgetnext() */ pos = ftello(pfp); status = getent(cap, &dummy, dbp, pfp, nbuf, 0, NULL) + 1; if (status > 0) fseeko(pfp, pos, SEEK_SET); done: serrno = errno; if (toprec != otoprec) { toprec = otoprec; topreclen = otopreclen; free(record); } if (status <= 0) (void)cgetclose(); errno = serrno; return (status); }
/* * Get an entry for terminal name in buffer bp, * from the termcap file. Parse is very rudimentary; * we just notice escaped newlines. */ int tgetent(char *bp, char *name) { return (getent(bp, name, conffile)); }