void parse_args(int argc, char* argv[]) { int ch; while((ch = getopt(argc, argv, "g:m:u:U")) != EOF) { switch(ch) { case 'm': opt_umask = strtoul(optarg, &optarg, 8); if(*optarg) usage("MASK is not a positive octal integer"); break; case 'g': opt_gid = parse_gid(optarg); break; case 'u': opt_uid = parse_uid(optarg); break; case 'U': opt_gid = parse_gid(getenv("GID")); opt_uid = parse_uid(getenv("UID")); break; default: usage(0); } } num_sockets = argc - optind; if(num_sockets <= 0) usage("You must specify at least one socket"); socket_names = argv + optind; sockets = calloc(num_sockets, sizeof(int)); }
/* auth_mysql_init: * Initialise the database connection driver. */ int auth_mysql_init() { char *hostname = NULL, *localhost = "localhost", *s; if (!config_get_string("auth-mysql-username")) { log_print(LOG_ERR, _("auth_mysql_init: no auth-mysql-username directive in config")); return 0; } if (!config_get_string("auth-mysql-password")) { log_print(LOG_WARNING, _("auth_mysql_init: no auth-mysql-password directive in config; using blank password")); } if (!config_get_string("auth-mysql-database")) { log_print(LOG_ERR, _("auth_mysql_init: no auth-mysql-database directive in config")); return 0; } if ((s = config_get_string("auth-mysql-hostname"))) hostname = s; else hostname = localhost; /* Obtain query templates. The special string `none' means `don't use * any query for this action'. */ if ((s = config_get_string("auth-mysql-pass-query"))) user_pass_query_template = s; if (strcmp(user_pass_query_template, "none") == 0) user_pass_query_template = NULL; if ((s = config_get_string("auth-mysql-apop-query"))) apop_query_template = s; if (strcmp(apop_query_template, "none") == 0) apop_query_template = NULL; /* This is an optional action to put a row into the database after a * successful login, for POP-before-SMTP relaying. */ if ((s = config_get_string("auth-mysql-onlogin-query"))) onlogin_query_template = s; /* Obtain gid to use */ if ((s = config_get_string("auth-mysql-mail-group"))) { if (!parse_gid(s, &mail_gid)) { log_print(LOG_ERR, _("auth_mysql_init: auth-mysql-mail-group directive `%s' does not make sense"), s); return 0; } use_gid = 1; } mysql_servers = tokens_new(hostname, " \t"); if (get_mysql_server() == -1) { /* No server has been found working. */ tokens_delete(mysql_servers); log_print(LOG_ERR, _("auth_mysql_init: aborting")); return 0; } mysql_driver_active = 1; return 1; }
int main(int argc, char *argv[]) { uid_t shift, range; int r; log_set_max_level(LOG_DEBUG); log_parse_environment(); log_open(); if (argc != 4) { log_error("Expected PATH SHIFT RANGE parameters."); return EXIT_FAILURE; } r = parse_uid(argv[2], &shift); if (r < 0) { log_error_errno(r, "Failed to parse UID shift %s.", argv[2]); return EXIT_FAILURE; } r = parse_gid(argv[3], &range); if (r < 0) { log_error_errno(r, "Failed to parse UID range %s.", argv[3]); return EXIT_FAILURE; } r = path_patch_uid(argv[1], shift, range); if (r < 0) { log_error_errno(r, "Failed to patch directory tree: %m"); return EXIT_FAILURE; } log_info("Changed: %s", yes_no(r)); return EXIT_SUCCESS; }
static int service_parse_privileges(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user, struct mail_storage_service_privileges *priv_r, const char **error_r) { const struct mail_user_settings *set = user->user_set; uid_t uid = (uid_t)-1; gid_t gid = (gid_t)-1; memset(priv_r, 0, sizeof(*priv_r)); if (*set->mail_uid != '\0') { if (!parse_uid(set->mail_uid, &uid, error_r)) { *error_r = t_strdup_printf("%s (from %s)", *error_r, user->uid_source); return -1; } if (uid < (uid_t)set->first_valid_uid || (set->last_valid_uid != 0 && uid > (uid_t)set->last_valid_uid)) { *error_r = t_strdup_printf( "Mail access for users with UID %s not permitted " "(see first_valid_uid in config file, uid from %s).", dec2str(uid), user->uid_source); return -1; } } priv_r->uid = uid; priv_r->uid_source = user->uid_source; if (*set->mail_gid != '\0') { if (!parse_gid(set->mail_gid, &gid, error_r)) { *error_r = t_strdup_printf("%s (from %s)", *error_r, user->gid_source); return -1; } if (gid < (gid_t)set->first_valid_gid || (set->last_valid_gid != 0 && gid > (gid_t)set->last_valid_gid)) { *error_r = t_strdup_printf( "Mail access for users with GID %s not permitted " "(see first_valid_gid in config file, gid from %s).", dec2str(gid), user->gid_source); return -1; } } priv_r->gid = gid; priv_r->gid_source = user->gid_source; /* variable strings are expanded in mail_user_init(), but we need the home and chroot sooner so do them separately here. */ priv_r->home = user_expand_varstr(ctx, user, priv_r, user->user_set->mail_home); priv_r->chroot = user_expand_varstr(ctx, user, priv_r, user->user_set->mail_chroot); return 0; }
void parse_args(int argc, char* argv[]) { int ch; while((ch = getopt(argc, argv, "g:u:U")) != EOF) { switch(ch) { case 'g': opt_gid = parse_gid(optarg); break; case 'u': opt_uid = parse_uid(optarg); break; case 'U': opt_gid = parse_gid(getenv("GID")); opt_uid = parse_uid(getenv("UID")); break; default: usage(0); } } if((argc - optind) % 2) usage("Missing port number"); num_sockets = (argc - optind) / 2; if(num_sockets <= 0) usage("You must specify at least one socket"); socket_names = argv + optind; sockets = calloc(num_sockets, sizeof(int)); }
static int condition_test_group(Condition *c) { gid_t id; int r; assert(c); assert(c->parameter); assert(c->type == CONDITION_GROUP); r = parse_gid(c->parameter, &id); if (r >= 0) return in_gid(id); /* Avoid any NSS lookups if we are PID1 */ if (getpid_cached() == 1) return streq(c->parameter, "root"); return in_group(c->parameter) > 0; }
int get_group_creds(const char **groupname, gid_t *gid) { struct group *g; gid_t id; assert(groupname); /* We enforce some special rules for gid=0: in order to avoid * NSS lookups for root we hardcode its data. */ if (streq(*groupname, "root") || streq(*groupname, "0")) { *groupname = "root"; if (gid) *gid = 0; return 0; } if (parse_gid(*groupname, &id) >= 0) { errno = 0; g = getgrgid(id); if (g) *groupname = g->gr_name; } else { errno = 0; g = getgrnam(*groupname); } if (!g) return errno > 0 ? -errno : -ESRCH; if (gid) { if (!gid_is_valid(g->gr_gid)) return -EBADMSG; *gid = g->gr_gid; } return 0; }
/* auth_flatfile_init: * Initialise the driver. Reads the config directives. */ int auth_flatfile_init(void) { char *s; int ret = 0; /* Obtain uid to use */ if ((s = config_get_string("auth-flatfile-mail-user"))) { if (!parse_uid(s, &virtual_uid)) { log_print(LOG_ERR, _("auth_flatfile_init: auth-flatfile-mail-user directive `%s' does not make sense"), s); goto fail; } } else { log_print(LOG_ERR, _("auth_flatfile_init: no auth-flatfile-mail-user directive in config")); goto fail; } /* Obtain gid to use */ if ((s = config_get_string("auth-flatfile-mail-group"))) { if (!parse_gid(s, &virtual_gid)) { log_print(LOG_ERR, _("auth_flatfile_init: auth-flatfile-mail-group directive `%s' does not make sense"), s); goto fail; } } else { log_print(LOG_ERR, _("auth_flatfile_init: no auth-flatfile-mail-group directive in config")); goto fail; } /* Obtain path template to passwd file */ if ((s = config_get_string("auth-flatfile-passwd-file"))) { user_passwd_file_template = s; } else { log_print(LOG_ERR, _("auth_flatfile_init: no auth-flatfile-passwd-file directive in config")); goto fail; } ret = 1; fail: return ret; }
int main(int argc, char* argv[]) { int r, j = 0; _cleanup_free_ char *p = NULL; ssize_t n; pid_t pid; uid_t uid; gid_t gid; struct iovec iovec[14]; _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL, *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t = NULL; prctl(PR_SET_DUMPABLE, 0); if (argc != _ARG_MAX) { log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); log_error("Invalid number of arguments passed from kernel."); r = -EINVAL; goto finish; } r = parse_pid(argv[ARG_PID], &pid); if (r < 0) { log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); log_error("Failed to parse PID."); goto finish; } if (cg_pid_get_unit(pid, &t) >= 0) { if (streq(t, SPECIAL_JOURNALD_SERVICE)) { /* Make sure we don't make use of the journal, * if it's the journal which is crashing */ log_set_target(LOG_TARGET_KMSG); log_open(); r = divert_coredump(); goto finish; } core_unit = strappend("COREDUMP_UNIT=", t); } else if (cg_pid_get_user_unit(pid, &t) >= 0) core_unit = strappend("COREDUMP_USER_UNIT=", t); if (core_unit) IOVEC_SET_STRING(iovec[j++], core_unit); /* OK, now we know it's not the journal, hence make use of * it */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); r = parse_uid(argv[ARG_UID], &uid); if (r < 0) { log_error("Failed to parse UID."); goto finish; } r = parse_gid(argv[ARG_GID], &gid); if (r < 0) { log_error("Failed to parse GID."); goto finish; } core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]); if (core_pid) IOVEC_SET_STRING(iovec[j++], core_pid); core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]); if (core_uid) IOVEC_SET_STRING(iovec[j++], core_uid); core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]); if (core_gid) IOVEC_SET_STRING(iovec[j++], core_gid); core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]); if (core_signal) IOVEC_SET_STRING(iovec[j++], core_signal); core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]); if (core_comm) IOVEC_SET_STRING(iovec[j++], core_comm); #ifdef HAVE_LOGIND if (sd_pid_get_session(pid, &t) >= 0) { core_session = strappend("COREDUMP_SESSION=", t); free(t); if (core_session) IOVEC_SET_STRING(iovec[j++], core_session); } #endif if (get_process_exe(pid, &t) >= 0) { core_exe = strappend("COREDUMP_EXE=", t); free(t); if (core_exe) IOVEC_SET_STRING(iovec[j++], core_exe); } if (get_process_cmdline(pid, 0, false, &t) >= 0) { core_cmdline = strappend("COREDUMP_CMDLINE=", t); free(t); if (core_cmdline) IOVEC_SET_STRING(iovec[j++], core_cmdline); } core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL); if (core_timestamp) IOVEC_SET_STRING(iovec[j++], core_timestamp); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL); if (core_message) IOVEC_SET_STRING(iovec[j++], core_message); /* Now, let's drop privileges to become the user who owns the * segfaulted process and allocate the coredump memory under * his uid. This also ensures that the credentials journald * will see are the ones of the coredumping user, thus making * sure the user himself gets access to the core dump. */ if (setresgid(gid, gid, gid) < 0 || setresuid(uid, uid, uid) < 0) { log_error("Failed to drop privileges: %m"); r = -errno; goto finish; } p = malloc(9 + COREDUMP_MAX); if (!p) { r = log_oom(); goto finish; } memcpy(p, "COREDUMP=", 9); n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false); if (n < 0) { log_error("Failed to read core dump data: %s", strerror(-n)); r = (int) n; goto finish; } iovec[j].iov_base = p; iovec[j].iov_len = 9 + n; j++; r = sd_journal_sendv(iovec, j); if (r < 0) log_error("Failed to send coredump: %s", strerror(-r)); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int main (int argc, char **argv) { char *pidfile=NULL, *jail=NULL, *exec=NULL; int uid=-1,gid=-1; unsigned int i; char **newargv; openlog(PROGRAMNAME, LOG_PID, LOG_DAEMON); { int c=0; char *tuser=NULL, *tgroup=NULL, *texec=NULL; while (c != -1) { int option_index = 0; static struct option long_options[] = { {"pidfile", required_argument, NULL, 'p'}, {"jail", required_argument, NULL, 'j'}, {"exec", required_argument, NULL, 'x'}, {"user", required_argument, NULL, 'u'}, {"group", required_argument, NULL, 'g'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; c = getopt_long(argc, argv, "j:p:u:g:x:hv",long_options, &option_index); switch (c) { case 'j': jail = ending_slash(optarg); break; case 'p': pidfile = strdup(optarg); break; case 'u': tuser = strdup(optarg); break; case 'g': tgroup = strdup(optarg); break; case 'x': texec = strdup(optarg); break; case 'h': case 'V': print_usage(); exit(1); } } uid = parse_uid(tuser); gid = parse_gid(tgroup); exec = test_jail_and_exec(jail,texec); /* construct the new argv from all leftover options */ newargv = malloc0((2 + argc - optind)*sizeof(char *)); newargv[0] = exec; c = 1; while (optind < argc) { newargv[c] = strdup(argv[optind]); c++; optind++; } free(tuser); free(tgroup); free(texec); } if (pidfile) { FILE *pidfilefd = fopen(pidfile, "w"); int pid = getpid(); if (pidfilefd && fprintf(pidfilefd, "%d",pid)>=0) { fclose(pidfilefd); } else { syslog(LOG_NOTICE, "failed to write PID into %s", pidfile); } } /* open file descriptors can be used to break out of a chroot, so we close all of them, except for stdin,stdout and stderr */ #ifdef OPEN_MAX i = OPEN_MAX; #elif defined(NOFILE) i = NOFILE; #else i = getdtablesize(); #endif while (--i > 2) { while (close(i) != 0 && errno == EINTR); } if (chdir(jail)) { syslog(LOG_ERR, "abort, could not change directory chdir() to the jail %s: %s", jail,strerror(errno)); exit(33); } if (chroot(jail)) { syslog(LOG_ERR, "abort, could not change root chroot() to the jail %s: %s", jail,strerror(errno)); exit(35); } if (gid != -1 && setgid(gid)<0) { syslog(LOG_ERR, "abort, could not setgid %d: %s", gid,strerror(errno)); exit(37); } if (uid != -1 && setuid(uid)<0) { syslog(LOG_ERR, "abort, could not setuid %d: %s", uid,strerror(errno)); exit(39); } syslog(LOG_NOTICE,"executing %s in jail %s",exec,jail); execv(exec, newargv); syslog(LOG_ERR, "error: failed to execute %s in jail %s: %s",exec,jail,strerror(errno)); exit(31); }
static int service_drop_privileges(struct mail_storage_service_user *user, struct mail_storage_service_privileges *priv, bool disallow_root, bool keep_setuid_root, bool setenv_only, const char **error_r) { const struct mail_user_settings *set = user->user_set; struct restrict_access_settings rset; uid_t current_euid, setuid_uid = 0; const char *cur_chroot, *error; current_euid = geteuid(); restrict_access_init(&rset); restrict_access_get_env(&rset); if (priv->uid != (uid_t)-1) { rset.uid = priv->uid; rset.uid_source = priv->uid_source; } else if (rset.uid == (uid_t)-1 && disallow_root && current_euid == 0) { *error_r = "User is missing UID (see mail_uid setting)"; return -1; } if (priv->gid != (gid_t)-1) { rset.gid = priv->gid; rset.gid_source = priv->gid_source; } else if (rset.gid == (gid_t)-1 && disallow_root && set->first_valid_gid > 0 && getegid() == 0) { *error_r = "User is missing GID (see mail_gid setting)"; return -1; } if (*set->mail_privileged_group != '\0') { if (!parse_gid(set->mail_privileged_group, &rset.privileged_gid, &error)) { *error_r = t_strdup_printf( "%s (in mail_privileged_group setting)", error); return -1; } } if (*set->mail_access_groups != '\0') { rset.extra_groups = t_strconcat(set->mail_access_groups, ",", rset.extra_groups, NULL); } rset.first_valid_gid = set->first_valid_gid; rset.last_valid_gid = set->last_valid_gid; rset.chroot_dir = *priv->chroot == '\0' ? NULL : priv->chroot; rset.system_groups_user = user->system_groups_user; cur_chroot = restrict_access_get_current_chroot(); if (cur_chroot != NULL) { /* we're already chrooted. make sure the chroots are equal. */ if (rset.chroot_dir == NULL) { *error_r = "Process is already chrooted, " "can't un-chroot for this user"; return -1; } if (strcmp(rset.chroot_dir, cur_chroot) != 0) { *error_r = t_strdup_printf( "Process is already chrooted to %s, " "can't chroot to %s", cur_chroot, priv->chroot); return -1; } /* chrooting to same directory where we're already chrooted */ rset.chroot_dir = NULL; } if (disallow_root && (rset.uid == 0 || (rset.uid == (uid_t)-1 && current_euid == 0))) { *error_r = "Mail access not allowed for root"; return -1; } if (keep_setuid_root) { if (current_euid != rset.uid) { if (current_euid != 0) { /* we're changing the UID, switch back to root first */ mail_storage_service_seteuid_root(); } setuid_uid = rset.uid; } rset.uid = (uid_t)-1; disallow_root = FALSE; } if (!setenv_only) { restrict_access(&rset, *priv->home == '\0' ? NULL : priv->home, disallow_root); } else { restrict_access_set_env(&rset); } if (setuid_uid != 0 && !setenv_only) { if (seteuid(setuid_uid) < 0) i_fatal("mail-storage-service: seteuid(%s) failed: %m", dec2str(setuid_uid)); } return 0; }
AlsaPMO::AlsaPMO(FAContext *context) : PhysicalMediaOutput(context) { uint32 deviceNameSize = 128; char scard[128]; snd_mixer_t *pMixer; char mixer_id[25]="Master"; m_properlyInitialized = false; myInfo = new OutputInfo(); memset(myInfo, 0, sizeof(OutputInfo)); m_pBufferThread = NULL; m_iOutputBufferSize = 0; m_iBytesPerSample = 0; m_iBaseTime = -1; m_iDataSize = 0; if (!m_pBufferThread) { m_pBufferThread = Thread::CreateThread(); assert(m_pBufferThread); m_pBufferThread->Create(AlsaPMO::StartWorkerThread, this); } m_handle = NULL; m_device = NULL; m_channels = -1; m_rate = -1; m_device = (char *) malloc(deviceNameSize); m_pContext->prefs->GetPrefString(kALSADevicePref, m_device, &deviceNameSize); if (m_device) { if (sscanf(m_device, "%[^:]: %d", scard, &m_iDevice) != 2) { ReportError("The ALSADevice statement in the preference file" "is improperly formatted. Format: ALSADevice: " "[card name/card number]:[device number]"); return; } m_iCard = snd_card_name(scard); if (m_iCard < 0) { ReportError("Invalid ALSA card name/number specified."); return; } if (m_iDevice < 0 || m_iDevice > 31) { ReportError("Invalid ALSA device number specified."); return; } } else m_iCard = m_iDevice = 0; switch (m_iDevice) { case 0: strncpy(mixer_id,"PCM",sizeof(mixer_id)); break; case 1: strncpy(mixer_id,"PCM1",sizeof(mixer_id)); break; } parse_gid(mixer_id, &m_gid); snd_mixer_open(&pMixer, m_iCard, 0); bzero(&m_group, sizeof(m_group)); m_group.gid = m_gid; if ((m_iChannel = snd_mixer_group_read(pMixer, &m_group )) < 0) { strncpy(mixer_id,"Master",sizeof(mixer_id)); parse_gid(mixer_id, &m_gid); m_group.gid = m_gid; m_iChannel = snd_mixer_group_read(pMixer, &m_group ); } snd_mixer_close(pMixer); delete m_device; }
/** * Parse permissions, including mount-time overrides. This is roughly the same behavior as * NTFS-3g, except that fmask and dmask override umask regardless of argument order. */ int permissions_setup(struct ltfs_fuse_data *priv) { mode_t mode; /* Set defaults */ priv->perm_override = false; priv->mount_uid = geteuid(); priv->mount_gid = getegid(); priv->file_mode = S_IFREG | 0777; priv->dir_mode = S_IFDIR | 0777; /* User ID override */ if (priv->force_uid) { priv->perm_override = true; priv->mount_uid = parse_uid(priv->force_uid); if (priv->mount_uid == (uid_t)-1) { /* Invalid UID */ ltfsmsg(LTFS_ERR, "14079E", priv->force_uid); return -1; } free(priv->force_uid); } /* Group ID override */ if (priv->force_gid) { priv->perm_override = true; priv->mount_gid = parse_gid(priv->force_gid); if (priv->mount_gid == (gid_t)-1) { /* Invalid GID */ ltfsmsg(LTFS_ERR, "14080E", priv->force_gid); return -1; } free(priv->force_gid); } /* Global (file and directory) permissions override */ if (priv->force_umask) { priv->perm_override = true; mode = parse_mode(priv->force_umask); if (mode == (mode_t)-1) { /* Invalid umask */ ltfsmsg(LTFS_ERR, "14006E", priv->force_umask); return -1; } priv->file_mode = (S_IFREG | 0777) & ~mode; priv->dir_mode = (S_IFDIR | 0777) & ~mode; free(priv->force_umask); } /* File permissions override */ if (priv->force_fmask) { priv->perm_override = true; mode = parse_mode(priv->force_fmask); if (mode == (mode_t)-1) { /* Invalid fmask */ ltfsmsg(LTFS_ERR, "14007E", priv->force_fmask); return -1; } priv->file_mode = (S_IFREG | 0777) & ~mode; free(priv->force_fmask); } /* Directory permissions override */ if (priv->force_dmask) { priv->perm_override = true; mode = parse_mode(priv->force_dmask); if (mode == (mode_t)-1) { /* Invalid dmask */ ltfsmsg(LTFS_ERR, "14008E", priv->force_dmask); return -1; } priv->dir_mode = (S_IFDIR | 0777) & ~mode; free(priv->force_dmask); } /* Uncomment to apply the current umask to the default permissions, as vfat does. mode = umask(0); umask(mode); if (! priv->force_umask && ! priv->force_fmask) priv->file_mode = (S_IFREG | 0777) & ~mode; if (! priv->force_umask && ! priv->force_dmask) priv->dir_mode = (S_IFDIR | 0777) & ~mode; */ return 0; }
int main(int argc, char* argv[]) { /* The small core field we allocate on the stack, to keep things simple */ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL, *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL, *core_slice = NULL; /* The larger ones we allocate on the heap */ _cleanup_free_ char *core_timestamp = NULL, *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL, *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL, *core_environ = NULL; _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL; const char *info[_INFO_LEN]; _cleanup_close_ int coredump_fd = -1; struct iovec iovec[26]; uint64_t coredump_size; int r, j = 0; uid_t uid, owner_uid; gid_t gid; pid_t pid; char *t; const char *p; /* Make sure we never enter a loop */ prctl(PR_SET_DUMPABLE, 0); /* First, log to a safe place, since we don't know what * crashed and it might be journald which we'd rather not log * to then. */ log_set_target(LOG_TARGET_KMSG); log_open(); if (argc < INFO_COMM + 1) { log_error("Not enough arguments passed from kernel (%d, expected %d).", argc - 1, INFO_COMM + 1 - 1); r = -EINVAL; goto finish; } /* Ignore all parse errors */ parse_config(); log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage)); log_debug("Selected compression %s.", yes_no(arg_compress)); r = parse_uid(argv[INFO_UID + 1], &uid); if (r < 0) { log_error("Failed to parse UID."); goto finish; } r = parse_pid(argv[INFO_PID + 1], &pid); if (r < 0) { log_error("Failed to parse PID."); goto finish; } r = parse_gid(argv[INFO_GID + 1], &gid); if (r < 0) { log_error("Failed to parse GID."); goto finish; } if (get_process_comm(pid, &comm) < 0) { log_warning("Failed to get COMM, falling back to the command line."); comm = strv_join(argv + INFO_COMM + 1, " "); } if (get_process_exe(pid, &exe) < 0) log_warning("Failed to get EXE."); info[INFO_PID] = argv[INFO_PID + 1]; info[INFO_UID] = argv[INFO_UID + 1]; info[INFO_GID] = argv[INFO_GID + 1]; info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1]; info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1]; info[INFO_COMM] = comm; info[INFO_EXE] = exe; if (cg_pid_get_unit(pid, &t) >= 0) { if (streq(t, SPECIAL_JOURNALD_SERVICE)) { free(t); /* If we are journald, we cut things short, * don't write to the journal, but still * create a coredump. */ if (arg_storage != COREDUMP_STORAGE_NONE) arg_storage = COREDUMP_STORAGE_EXTERNAL; r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); if (r < 0) goto finish; r = maybe_remove_external_coredump(filename, coredump_size); if (r < 0) goto finish; log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename); goto finish; } core_unit = strjoina("COREDUMP_UNIT=", t); free(t); } else if (cg_pid_get_user_unit(pid, &t) >= 0) { core_unit = strjoina("COREDUMP_USER_UNIT=", t); free(t); } if (core_unit) IOVEC_SET_STRING(iovec[j++], core_unit); /* OK, now we know it's not the journal, hence we can make use * of it now. */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); core_pid = strjoina("COREDUMP_PID=", info[INFO_PID]); IOVEC_SET_STRING(iovec[j++], core_pid); core_uid = strjoina("COREDUMP_UID=", info[INFO_UID]); IOVEC_SET_STRING(iovec[j++], core_uid); core_gid = strjoina("COREDUMP_GID=", info[INFO_GID]); IOVEC_SET_STRING(iovec[j++], core_gid); core_signal = strjoina("COREDUMP_SIGNAL=", info[INFO_SIGNAL]); IOVEC_SET_STRING(iovec[j++], core_signal); if (sd_pid_get_session(pid, &t) >= 0) { core_session = strjoina("COREDUMP_SESSION=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_session); } if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) { r = asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid); if (r > 0) IOVEC_SET_STRING(iovec[j++], core_owner_uid); } if (sd_pid_get_slice(pid, &t) >= 0) { core_slice = strjoina("COREDUMP_SLICE=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_slice); } if (comm) { core_comm = strjoina("COREDUMP_COMM=", comm); IOVEC_SET_STRING(iovec[j++], core_comm); } if (exe) { core_exe = strjoina("COREDUMP_EXE=", exe); IOVEC_SET_STRING(iovec[j++], core_exe); } if (get_process_cmdline(pid, 0, false, &t) >= 0) { core_cmdline = strjoina("COREDUMP_CMDLINE=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cmdline); } if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) { core_cgroup = strjoina("COREDUMP_CGROUP=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cgroup); } if (compose_open_fds(pid, &t) >= 0) { core_open_fds = strappend("COREDUMP_OPEN_FDS=", t); free(t); if (core_open_fds) IOVEC_SET_STRING(iovec[j++], core_open_fds); } p = procfs_file_alloca(pid, "status"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_status = strappend("COREDUMP_PROC_STATUS=", t); free(t); if (core_proc_status) IOVEC_SET_STRING(iovec[j++], core_proc_status); } p = procfs_file_alloca(pid, "maps"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t); free(t); if (core_proc_maps) IOVEC_SET_STRING(iovec[j++], core_proc_maps); } p = procfs_file_alloca(pid, "limits"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t); free(t); if (core_proc_limits) IOVEC_SET_STRING(iovec[j++], core_proc_limits); } p = procfs_file_alloca(pid, "cgroup"); if (read_full_file(p, &t, NULL) >=0) { core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t); free(t); if (core_proc_cgroup) IOVEC_SET_STRING(iovec[j++], core_proc_cgroup); } if (get_process_cwd(pid, &t) >= 0) { core_cwd = strjoina("COREDUMP_CWD=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cwd); } if (get_process_root(pid, &t) >= 0) { core_root = strjoina("COREDUMP_ROOT=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_root); } if (get_process_environ(pid, &t) >= 0) { core_environ = strappend("COREDUMP_ENVIRON=", t); free(t); if (core_environ) IOVEC_SET_STRING(iovec[j++], core_environ); } core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL); if (core_timestamp) IOVEC_SET_STRING(iovec[j++], core_timestamp); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); /* Vacuum before we write anything again */ coredump_vacuum(-1, arg_keep_free, arg_max_use); /* Always stream the coredump to disk, if that's possible */ r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); if (r < 0) /* skip whole core dumping part */ goto log; /* If we don't want to keep the coredump on disk, remove it * now, as later on we will lack the privileges for * it. However, we keep the fd to it, so that we can still * process it and log it. */ r = maybe_remove_external_coredump(filename, coredump_size); if (r < 0) goto finish; if (r == 0) { const char *coredump_filename; coredump_filename = strjoina("COREDUMP_FILENAME=", filename); IOVEC_SET_STRING(iovec[j++], coredump_filename); } /* Vacuum again, but exclude the coredump we just created */ coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use); /* Now, let's drop privileges to become the user who owns the * segfaulted process and allocate the coredump memory under * the user's uid. This also ensures that the credentials * journald will see are the ones of the coredumping user, * thus making sure the user gets access to the core * dump. Let's also get rid of all capabilities, if we run as * root, we won't need them anymore. */ r = drop_privileges(uid, gid, 0); if (r < 0) { log_error_errno(r, "Failed to drop privileges: %m"); goto finish; } #ifdef HAVE_ELFUTILS /* Try to get a strack trace if we can */ if (coredump_size <= arg_process_size_max) { _cleanup_free_ char *stacktrace = NULL; r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace); if (r >= 0) core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL); else if (r == -EINVAL) log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno())); else log_warning_errno(r, "Failed to generate stack trace: %m"); } if (!core_message) #endif log: core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL); if (core_message) IOVEC_SET_STRING(iovec[j++], core_message); /* Optionally store the entire coredump in the journal */ if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) && coredump_size <= arg_journal_size_max) { size_t sz = 0; /* Store the coredump itself in the journal */ r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz); if (r >= 0) { iovec[j].iov_base = coredump_data; iovec[j].iov_len = sz; j++; } } r = sd_journal_sendv(iovec, j); if (r < 0) log_error_errno(r, "Failed to log coredump: %m"); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int main(int argc, char *argv[]) { struct iovec *iov; int ch, iovlen; char source [MAXPATHLEN], target[MAXPATHLEN], errmsg[255]; char uid_str[20], gid_str[20]; char fstype[] = "unionfs"; char *p, *val; iov = NULL; iovlen = 0; memset(errmsg, 0, sizeof(errmsg)); while ((ch = getopt(argc, argv, "bo:")) != -1) { switch (ch) { case 'b': printf("\n -b is deprecated. Use \"-o below\" instead\n"); build_iovec(&iov, &iovlen, "below", NULL, 0); break; case 'o': p = strchr(optarg, '='); val = NULL; if (p != NULL) { *p = '\0'; val = p + 1; if (strcmp(optarg, "gid") == 0) { parse_gid(val, gid_str, sizeof(gid_str)); val = gid_str; } else if (strcmp(optarg, "uid") == 0) { parse_uid(val, uid_str, sizeof(uid_str)); val = uid_str; } } build_iovec(&iov, &iovlen, optarg, val, (size_t)-1); break; case '?': default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 2) usage(); /* resolve both target and source with realpath(3) */ if (checkpath(argv[0], target) != 0) err(EX_USAGE, "%s", target); if (checkpath(argv[1], source) != 0) err(EX_USAGE, "%s", source); if (subdir(target, source) || subdir(source, target)) errx(EX_USAGE, "%s (%s) and %s (%s) are not distinct paths", argv[0], target, argv[1], source); build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1); build_iovec(&iov, &iovlen, "fspath", source, (size_t)-1); build_iovec(&iov, &iovlen, "from", target, (size_t)-1); build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); if (nmount(iov, iovlen, 0)) err(EX_OSERR, "%s: %s", source, errmsg); exit(0); }
int change_uid_gid(const char *user, char **_home) { char line[LINE_MAX], *x, *u, *g, *h; const char *word, *state; _cleanup_free_ uid_t *uids = NULL; _cleanup_free_ char *home = NULL; _cleanup_fclose_ FILE *f = NULL; _cleanup_close_ int fd = -1; unsigned n_uids = 0; size_t sz = 0, l; uid_t uid; gid_t gid; pid_t pid; int r; assert(_home); if (!user || streq(user, "root") || streq(user, "0")) { /* Reset everything fully to 0, just in case */ r = reset_uid_gid(); if (r < 0) return log_error_errno(r, "Failed to become root: %m"); *_home = NULL; return 0; } /* First, get user credentials */ fd = spawn_getent("passwd", user, &pid); if (fd < 0) return fd; f = fdopen(fd, "r"); if (!f) return log_oom(); fd = -1; if (!fgets(line, sizeof(line), f)) { if (!ferror(f)) { log_error("Failed to resolve user %s.", user); return -ESRCH; } log_error_errno(errno, "Failed to read from getent: %m"); return -errno; } truncate_nl(line); wait_for_terminate_and_warn("getent passwd", pid, true); x = strchr(line, ':'); if (!x) { log_error("/etc/passwd entry has invalid user field."); return -EIO; } u = strchr(x+1, ':'); if (!u) { log_error("/etc/passwd entry has invalid password field."); return -EIO; } u++; g = strchr(u, ':'); if (!g) { log_error("/etc/passwd entry has invalid UID field."); return -EIO; } *g = 0; g++; x = strchr(g, ':'); if (!x) { log_error("/etc/passwd entry has invalid GID field."); return -EIO; } *x = 0; h = strchr(x+1, ':'); if (!h) { log_error("/etc/passwd entry has invalid GECOS field."); return -EIO; } h++; x = strchr(h, ':'); if (!x) { log_error("/etc/passwd entry has invalid home directory field."); return -EIO; } *x = 0; r = parse_uid(u, &uid); if (r < 0) { log_error("Failed to parse UID of user."); return -EIO; } r = parse_gid(g, &gid); if (r < 0) { log_error("Failed to parse GID of user."); return -EIO; } home = strdup(h); if (!home) return log_oom(); /* Second, get group memberships */ fd = spawn_getent("initgroups", user, &pid); if (fd < 0) return fd; fclose(f); f = fdopen(fd, "r"); if (!f) return log_oom(); fd = -1; if (!fgets(line, sizeof(line), f)) { if (!ferror(f)) { log_error("Failed to resolve user %s.", user); return -ESRCH; } log_error_errno(errno, "Failed to read from getent: %m"); return -errno; } truncate_nl(line); wait_for_terminate_and_warn("getent initgroups", pid, true); /* Skip over the username and subsequent separator whitespace */ x = line; x += strcspn(x, WHITESPACE); x += strspn(x, WHITESPACE); FOREACH_WORD(word, l, x, state) { char c[l+1]; memcpy(c, word, l); c[l] = 0; if (!GREEDY_REALLOC(uids, sz, n_uids+1)) return log_oom(); r = parse_uid(c, &uids[n_uids++]); if (r < 0) { log_error("Failed to parse group data from getent."); return -EIO; } }