static void execCmdline(strlist_t *cmdline, strlist_t *env, const char *workdir) { custr_t *execname; execname = execName(strlist_get(cmdline, 0), env, workdir); dlog("EXECNAME \"%s\"\n", custr_cstr(execname)); /* * We need to drop privs *after* we've setup /dev/zfd/[0-2] since that * requires being root. */ dlog("DROP PRIVS\n"); if (grp != NULL) { if (setgid(grp->gr_gid) != 0) { fatal(ERR_SETGID, "setgid(%d): %s\n", grp->gr_gid, strerror(errno)); } } if (pwd != NULL) { if (initgroups(pwd->pw_name, grp->gr_gid) != 0) { fatal(ERR_INITGROUPS, "initgroups(%s,%d): %s\n", pwd->pw_name, grp->gr_gid, strerror(errno)); } if (setuid(pwd->pw_uid) != 0) { fatal(ERR_SETUID, "setuid(%d): %s\n", pwd->pw_uid, strerror(errno)); } } execve(custr_cstr(execname), strlist_array(cmdline), strlist_array(env)); fatal(ERR_EXEC_FAILED, "execve(%s) failed: %s\n", execname, strerror(errno)); }
static me_cb_ret_t record_zoneinfo(manifest_ent_t *me, void *arg) { tzcheck_t *tzc = arg; tzent_t *tze; avl_index_t where; /* * We care only for records within the time zone database * directory. */ if (strncmp(custr_cstr(tzc->tzc_prefix), me->me_name, custr_len(tzc->tzc_prefix)) != 0) { return (MECB_NEXT); } if ((tze = calloc(1, sizeof (*tze))) == NULL) { err(1, "alloc failure"); } tze->tze_path = strdup(me->me_name + custr_len(tzc->tzc_prefix)); switch (me->me_type) { case ME_TYPE_HARDLINK: if (strncmp(me->me_target, custr_cstr(tzc->tzc_prefix), custr_len(tzc->tzc_prefix)) != 0) { errx(1, "hardlink \"%s\" target did not begin " "with correct prefix (%s)", me->me_target, custr_cstr(tzc->tzc_prefix)); } tze->tze_target = strdup(me->me_target + custr_len(tzc->tzc_prefix)); tze->tze_type = me->me_type; break; case ME_TYPE_SYMLINK: tze->tze_target = strdup(me->me_target); /* FALLTHRU */ case ME_TYPE_DIRECTORY: case ME_TYPE_FILE: tze->tze_type = me->me_type; break; default: errx(1, "unexpected type (%d) of \"%s\" in manifest", me->me_type, me->me_name); } if (avl_find(&tzc->tzc_zoneinfo_manifest, tze, &where) != NULL) { errx(1, "path \"%s\" in manifest twice", me->me_name); } avl_insert(&tzc->tzc_zoneinfo_manifest, tze, where); return (MECB_NEXT); }
int split_on(const char *line, char delim, strlist_t *sl) { custr_t *cu = NULL; int error = 0; const char *c = line; if (custr_alloc(&cu) != 0) { error = errno; goto out; } for (;;) { char cc = *c++; if (cc == '\0') { if (custr_len(cu) > 0 && strlist_set_tail(sl, custr_cstr(cu)) != 0) { error = errno; } goto out; } else if (cc == delim) { if (strlist_set_tail(sl, custr_cstr(cu)) != 0) { error = errno; goto out; } custr_reset(cu); } else { if (custr_appendc(cu, cc) != 0) { error = errno; goto out; } } } out: custr_free(cu); errno = error; return (error == 0 ? 0 : -1); }
void receipt(struct message *mp) { char head[LINESIZE]; char buf[BUFSIZ]; FILE *pp, *fp; char *mail, *s; if ((mail = value("sendmail")) == 0) #ifdef SENDMAIL mail = SENDMAIL; #else mail = MAIL; #endif if (icsubstr(hfield("default-options", mp, addone), "/receipt") || icsubstr(hfield(">to", mp, addto), "/receipt")) { snprintf(buf, sizeof (buf), "%s %s", mail, skin(nameof(mp))); if (pp = npopen(buf, "w")) { headline_t *hl; if (headline_alloc(&hl) != 0) { err(1, "could not allocate memory"); } fp = setinput(mp); readline(fp, head); if (parse_headline(head, hl) != 0) { headline_reset(hl); } if (custr_len(hl->hl_date) > 0) { fprintf(pp, "Original-Date: %s\n", custr_cstr(hl->hl_date)); } if (s = hfield("message-id", mp, addone)) fprintf(pp, "Original-Message-ID: %s\n", s); s = hfield("subject", mp, addone); fprintf(pp, "Subject: RR: %s\n", s ? s : "(none)"); npclose(pp); headline_free(hl); } } }
int main(int argc, char *argv[]) { custr_t *execname = NULL; strlist_t *env = NULL; custr_t *workdir = NULL; /* * We write the log to stderr and expect cn-agent to log/parse the output. * It can know that dockerexec finished when it sees either a line that * starts with: * * <timestamp> FATAL * * or: * * <timestamp> EXEC * * the former indicating that we failed and the latter that the next action * will be execve(). */ log_stream = stderr; if (argc < 2) { fatal(ERR_NO_COMMAND, "no command specified on cmdline, argc: %d\n", argc); } if (strlist_alloc(&env, 0) != 0) { fatal(ERR_NO_MEMORY, "failed to allocate string lists: %s", strerror(errno)); } /* NOTE: all of these will call fatal() if there's a problem */ getUserGroupData(); setupWorkdir(&workdir); if (buildCmdEnv(env) != 0) { fatal(ERR_UNEXPECTED, "buildCmdEnv() failed: %s\n", strerror(errno)); } /* cleanup mess from mdata-client */ close(4); /* /dev/urandom from mdata-client */ close(5); /* event port from mdata-client */ close(6); /* /native/.zonecontrol/metadata.sock from mdata-client */ /* TODO: ensure we cleaned up everything else mdata created for us */ // TODO: close any descriptors which are not to be attached to this // exec cmd? Or let the zlogin caller deal with that? dlog("DROP PRIVS\n"); if (grp != NULL) { if (setgid(grp->gr_gid) != 0) { fatal(ERR_SETGID, "setgid(%d): %s\n", grp->gr_gid, strerror(errno)); } } if (pwd != NULL) { if (initgroups(pwd->pw_name, grp->gr_gid) != 0) { fatal(ERR_INITGROUPS, "initgroups(%s,%d): %s\n", pwd->pw_name, grp->gr_gid, strerror(errno)); } if (setuid(pwd->pw_uid) != 0) { fatal(ERR_SETUID, "setuid(%d): %s\n", pwd->pw_uid, strerror(errno)); } } /* * Find the executable path based on argv[1] and $PATH. This routine * calls fatal() if it fails. */ execname = execName(argv[1], env, custr_cstr(workdir)); // Message for cn-agent that dockerexec is done and child should start // now. dlog("EXEC\n"); execve(custr_cstr(execname), argv + 1, strlist_array(env)); // If execve() has failed, this next message should go to the user since // stdout and stderr should now be connected to them. fatal(ERR_EXEC_FAILED, "execve(%s) failed: %s\n", argv[1], strerror(errno)); /* NOTREACHED */ abort(); }
static void mkprog(struct sym_test *st) { char *s = NULL; custr_reset(st_custr); for (int i = 0; i < MAXHDR && st->st_hdrs[i] != NULL; i++) { addprogfmt("#include <%s>\n", st->st_hdrs[i]); } if (st->st_rtype != NULL) { for (s = st->st_rtype; *s; s++) { addprogch(*s); if (*s == '(') { s++; addprogch(*s); s++; break; } } addprogch(' '); } /* for function pointers, s is closing suffix, otherwise empty */ switch (st->st_type) { case SYM_TYPE: addprogstr("test_type;"); break; case SYM_VALUE: addprogfmt("test_value%s;\n", s); /* s usually empty */ addprogstr("void\ntest_func(void)\n{\n"); addprogfmt("\ttest_value = %s;\n}", st->st_name); break; case SYM_DEFINE: addprogfmt("#if !defined(%s)", st->st_name); if (st->st_defval != NULL) addprogfmt("|| %s != %s", st->st_name, st->st_defval); addprogfmt("\n#error %s is not defined or has the wrong value", st->st_name); addprogfmt("\n#endif\n"); break; case SYM_FUNC: addprogstr("\ntest_func("); for (int i = 0; st->st_atypes[i] != NULL && i < MAXARG; i++) { int didname = 0; if (i > 0) { addprogstr(", "); } if (strcmp(st->st_atypes[i], "void") == 0) { didname = 1; } if (strcmp(st->st_atypes[i], "") == 0) { didname = 1; addprogstr("void"); } /* print the argument list */ for (char *a = st->st_atypes[i]; *a; a++) { if (*a == '(' && a[1] == '*' && !didname) { addprogfmt("(*a%d", i); didname = 1; a++; } else if (*a == '[' && !didname) { addprogfmt("a%d[", i); didname = 1; } else { addprogch(*a); } } if (!didname) { addprogfmt(" a%d", i); } } if (st->st_atypes[0] == NULL) { addprogstr("void"); } /* * Close argument list, and closing ")" for func ptrs. * Note that for non-function pointers, s will be empty * below, otherwise it points to the trailing argument * list. */ addprogfmt(")%s\n{\n\t", s); if (strcmp(st->st_rtype, "") != 0 && strcmp(st->st_rtype, "void") != 0) { addprogstr("return "); } /* add the function call */ addprogfmt("%s(", st->st_name); for (int i = 0; st->st_atypes[i] != NULL && i < MAXARG; i++) { if (strcmp(st->st_atypes[i], "") != 0 && strcmp(st->st_atypes[i], "void") != 0) { addprogfmt("%sa%d", i > 0 ? ", " : "", i); } } addprogstr(");\n}"); break; } addprogch('\n'); st->st_prog = custr_cstr(st_custr); }
int parse_line(const char *line, strlist_t *sl) { custr_t *cu = NULL; state_t state = ST_WHITESPACE; const char *c = line; int error = 0; if (custr_alloc(&cu) != 0) { error = errno; goto out; } for (;;) { char cc = *c; lextype_t lextype; /* * Determine which class of character this is: */ switch (cc) { case '\0': case '#': case '\n': case '\r': lextype = LEX_ENDL; break; case ' ': case '\t': lextype = LEX_WHITESPACE; break; default: lextype = LEX_OTHER; break; } /* * Determine what to do with this character based on the class * and our current state: */ switch (state) { case ST_WHITESPACE: { switch (lextype) { case LEX_ENDL: goto out; case LEX_WHITESPACE: c++; break; case LEX_OTHER: state = ST_TOKEN; break; default: (void) printf("ST_WHITESPACE: unknown " "lextype: %d\n", lextype); abort(); } break; } case ST_TOKEN: { switch (lextype) { case LEX_ENDL: if (strlist_set_tail(sl, custr_cstr(cu)) != 0) { error = errno; goto out; } goto out; case LEX_WHITESPACE: if (strlist_set_tail(sl, custr_cstr(cu)) != 0) { error = errno; goto out; } custr_reset(cu); state = ST_WHITESPACE; break; case LEX_OTHER: if (custr_appendc(cu, cc) != 0) { error = errno; goto out; } c++; break; default: (void) printf("ST_TOKEN: unknown lextype: %d\n", lextype); abort(); } break; } default: (void) printf("unknown state: %d\n", state); abort(); } } out: custr_free(cu); errno = error; return (error == 0 ? 0 : -1); }