+ /* Ok, we have an applet name. Process the rhs if this
+ * applet is currently built in and ignore it otherwise.
+ * Note: This can hide config file bugs which only pop
+ * up when the busybox configuration is changed. */
+ if ((applet = find_applet_by_name(s))) {
+ /* Note: We currently don't check for duplicates!
+ * The last config line for each applet will be the
+ * one used since we insert at the head of the list.
+ * I suppose this could be considered a feature. */
+ sct = xmalloc(sizeof(struct BB_suid_config));
+ sct->m_applet = applet;
+ sct->m_mode = 0;
+ sct->m_next = sct_head;
+ sct_head = sct;
+
+ /* Get the specified mode. */
+
+ e = (char *) bb_skip_whitespace(e+1);
+
+ for (i=0 ; i < 3 ; i++) {
+ const char *q;
+ if (!*(q = strchrnul(mode_chars + 5*i, *e++))) {
+ parse_error("mode");
+ }
+ /* Adjust by -i to account for nul. */
+ sct->m_mode |= mode_mask[(q - mode_chars) - i];
+ }
+
+ /* Now get the the user/group info. */
+
+ s = (char *) bb_skip_whitespace(e);
+
+ /* Note: We require whitespace between the mode and the
+ * user/group info. */
+ if ((s == e) || !(e = strchr(s, '.'))) {
+ parse_error("<uid>.<gid>");
+ }
+ *e++ = 0;
+
+ /* We can't use get_ug_id here since it would exit()
+ * if a uid or gid was not found. Oh well... */
+ {
+ char *e2;
+
+ sct->m_uid = strtoul(s, &e2, 10);
+ if (*e2 || (s == e2)) {
+ struct passwd *pwd;
+ if (!(pwd = getpwnam(s))) {
+ parse_error("user");
+ }
+ sct->m_uid = pwd->pw_uid;
+ }
+
+ sct->m_gid = strtoul(e, &e2, 10);
+ if (*e2 || (e == e2)) {
+ struct group *grp;
+ if (!(grp = getgrnam(e))) {
+ parse_error("group");
+ }
+ sct->m_gid = grp->gr_gid;
+ }
+ }
+ }
+ continue;
+ }
+
+ /* Unknown sections are ignored. */
+
+ /* Encountering configuration lines prior to seeing a
+ * section header is treated as an error. This is how
+ * the old code worked, but it may not be desirable.
+ * We may want to simply ignore such lines in case they
+ * are used in some future version of busybox. */
+ if (!section) {
+ parse_error("keyword outside section");
+ }
+
+ } while (1);
+
+ pe_label:
+ fprintf(stderr, "Parse error in %s, line %d: %s\n",
+ config_file, lc, err);
+
+ fclose(f);
+ /* Release any allocated memory before returning. */
+ while (sct_head) {
+ sct = sct_head->m_next;
+ free(sct_head);
+ sct_head = sct;
+ }
+ return;
+}
+
+#else
+#define parse_config_file(x)
+#endif /* CONFIG_FEATURE_SUID_CONFIG */
+
+#ifdef CONFIG_FEATURE_SUID
+static void check_suid (struct BB_applet *applet)
+{
+ uid_t ruid = getuid (); /* real [ug]id */
+ uid_t rgid = getgid ();
+
+#ifdef CONFIG_FEATURE_SUID_CONFIG
+ if (suid_cfg_readable) {
+ struct BB_suid_config *sct;
+
+ for (sct = suid_config; sct; sct = sct->m_next) {
+ if (sct->m_applet == applet)
+ break;
+ }
+ if (sct) {
+ mode_t m = sct->m_mode;
+
+ if (sct->m_uid == ruid) /* same uid */
+ m >>= 6;
+ else if ((sct->m_gid == rgid) || ingroup (ruid, sct->m_gid)) /* same group / in group */
+ m >>= 3;
+
+ if (!(m & S_IXOTH)) /* is x bit not set ? */
+ bb_error_msg_and_die ("You have no permission to run this applet!");
+
+ if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { /* *both* have to be set for sgid */
+ if (setegid (sct->m_gid))
+ bb_error_msg_and_die
+ ("BusyBox binary has insufficient rights to set proper GID for applet!");
+ } else
+ setgid (rgid); /* no sgid -> drop */
+
+ if (sct->m_mode & S_ISUID) {
+ if (seteuid (sct->m_uid))
+ bb_error_msg_and_die
+ ("BusyBox binary has insufficient rights to set proper UID for applet!");
+ } else
+ setuid (ruid); /* no suid -> drop */
+ } else {
+ /* default: drop all priviledges */
+ setgid (rgid);
+ setuid (ruid);
+ }
+ return;
+ } else {
+#ifndef CONFIG_FEATURE_SUID_CONFIG_QUIET
+ static int onetime = 0;
+
+ if (!onetime) {
+ onetime = 1;
+ fprintf (stderr, "Using fallback suid method\n");
+ }
+#endif
+ }
+#endif
+
+ if (applet->need_suid == _BB_SUID_ALWAYS) {
+ if (geteuid () != 0)
+ bb_error_msg_and_die ("This applet requires root priviledges!");
+ } else if (applet->need_suid == _BB_SUID_NEVER) {
+ setgid (rgid); /* drop all priviledges */
+ setuid (ruid);
+ }
+}
+#else
+#define check_suid(x)
+#endif /* CONFIG_FEATURE_SUID */
+
+
+
+
+
+extern void bb_show_usage (void)
+{
+ const char *format_string;
+ const char *usage_string = usage_messages;
+ int i;
+
+ for (i = applet_using - applets; i > 0;) {
+ if (!*usage_string++) {
+ --i;
+ }
+ }
+
+ format_string = "%s\n\nUsage: %s %s\n\n";
+ if (*usage_string == '\b')
+ format_string = "%s\n\nNo help available.\n\n";
+ fprintf (stderr, format_string, bb_msg_full_version, applet_using->name,
+ usage_string);
+
+ exit (EXIT_FAILURE);
+}
+
+static int applet_name_compare (const void *x, const void *y)
+{
+ const char *name = x;
+ const struct BB_applet *applet = y;
+
+ return strcmp (name, applet->name);