Ошибка аутентификации в приложении pam без запроса пароля - PullRequest
2 голосов
/ 26 марта 2019

У меня есть приложение, работающее от непривилегированного пользователя, но в какой-то момент эта программа должна запустить еще одну в качестве пользователя root, было бы неплохо, если бы я мог повторно использовать настроенный модуль PAM, например, su, sudo, login или кого-либо еще.

Поэтому я пытаюсь написать некоторый код для аутентификации root и запустить эту программу с использованием PAM, как это делает sudo, но я не могу запросить пароль, он должен быть автоматическим. Эта непривилегированная программа в определенное время будет иметь доступ к паролю root.

Попробовал этот пример здесь https://www.netbsd.org/docs/guide/en/chap-pam.html но на pam_authenticate всегда возвращается PAM_AUTH_ERR, я попробовал все сконфигурированные модули на моем Ubuntu 18.04.

#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
#include <sys/wait.h>
#include <err.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <grp.h>
#include <assert.h>

#include <string>
#include <vector>

int converse(int n, const struct pam_message **msg, struct pam_response **resp, void *data)
{
   struct pam_response *aresp;
   char buf[PAM_MAX_RESP_SIZE];
   int i;

   data = data;
   if (n <= 0 || n > PAM_MAX_NUM_MSG)
      return (PAM_CONV_ERR);
   if ((aresp = (struct pam_response *) calloc(n, sizeof *aresp)) == NULL)
      return (PAM_BUF_ERR);
   for (i = 0; i < n; ++i) {
      aresp[i].resp_retcode = 0;
      aresp[i].resp = NULL;
      switch (msg[i]->msg_style) {
         case PAM_PROMPT_ECHO_OFF:
            //aresp[i].resp = strdup(getpass(msg[i]->msg));
            aresp[i].resp = strdup("mypass");
            aresp[i].resp_retcode = 0;
            if (aresp[i].resp == NULL)
               goto fail;
            break;
         case PAM_PROMPT_ECHO_ON:
            fputs(msg[i]->msg, stderr);
            if (fgets(buf, sizeof buf, stdin) == NULL)
               goto fail;
            aresp[i].resp = strdup(buf);
            if (aresp[i].resp == NULL)
               goto fail;
            break;
         case PAM_ERROR_MSG:
            fputs(msg[i]->msg, stderr);
            if (strlen(msg[i]->msg) > 0 &&
                msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
               fputc('\n', stderr);
            break;
         case PAM_TEXT_INFO:
            fputs(msg[i]->msg, stdout);
            if (strlen(msg[i]->msg) > 0 &&
                msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
               fputc('\n', stdout);
            break;
         default:
            goto fail;
      }
   }
   *resp = aresp;
   return (PAM_SUCCESS);

   fail:
   for (i = 0; i < n; ++i) {
      if (aresp[i].resp != NULL) {
         memset(aresp[i].resp, 0, strlen(aresp[i].resp));
         free(aresp[i].resp);
      }
   }
   memset(aresp, 0, n * sizeof *aresp);
   *resp = NULL;
   return (PAM_CONV_ERR);
}

static struct pam_conv conv = {
      converse,
      //misc_conv,
      NULL
};

extern char **environ;

static pam_handle_t *pamh;
static struct pam_conv pamc;

static void
usage(void)
{

   fprintf(stderr, "Usage: su [login [args]]\n");
   exit(1);
}

int
main(int argc, char *argv[])
{
   char hostname[64];
   const char *user, *tty;
   char **args, **pam_envlist, **pam_env;
   struct passwd *pwd;
   int o, pam_err, status;
   pid_t pid;

   while ((o = getopt(argc, argv, "h")) != -1)
      switch (o) {
         case 'h':
         default:
            usage();
      }

   argc -= optind;
   argv += optind;

   if (argc > 0) {
      user = *argv;
      --argc;
      ++argv;
   } else {
      user = "root";
   }

   int pam_status = PAM_SUCCESS;
   /* initialize PAM */
   //pamc.conv = &openpam_ttyconv;

   if ((pam_status = pam_start("passwd", user, &conv, &pamh)) != PAM_SUCCESS)
   {
      assert(false);
   }

   /* set some items */
   gethostname(hostname, sizeof(hostname));
   if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
   {
      assert(false);
   }

   user = getlogin();
   if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
   {
      assert(false);
   }
   tty = ttyname(STDERR_FILENO);
   if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
   {
      assert(false);
   }

   /* authenticate the applicant */
   pam_err = pam_authenticate(pamh, PAM_SILENT);
   if (pam_err != PAM_SUCCESS)
   {
      printf("Pam Error (%d)\n", pam_err);
      warn("pam_authenticate");
      assert(false);
   }

   printf("AUTHENTICATED ;-)");
   assert(false);
   if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
      pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
   if (pam_err != PAM_SUCCESS)
   {
      assert(false);
   }

   /* establish the requested credentials */
   if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
   {
      assert(false);
   }

   /* authentication succeeded; open a session */
   if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
   {
      assert(false);
   }

   /* get mapped user name; PAM may have changed it */
   pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
   if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
   {
      assert(false);
   }

   /* export PAM environment */
   if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
      for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
         putenv(*pam_env);
         free(*pam_env);
      }
      free(pam_envlist);
   }

   std::vector<std::string> arguments;
   arguments.resize(argc + 2);
   char * args_ptr [arguments.size()];

   arguments[0] = pwd->pw_shell;

   args_ptr[argc +1] = NULL;
   args_ptr[0] = (char *)arguments[0].c_str();
   for (int i = 0; i < argc; i++)
   {
      arguments[i + 1] = argv[i];
      args_ptr[i+1] = (char *)arguments[i+1].c_str();
   }
         /* set uid and groups */
         if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
            warn("initgroups()");
            _exit(1);
         }
         if (setgid(pwd->pw_gid) == -1) {
            warn("setgid()");
            _exit(1);
         }
         if (setuid(pwd->pw_uid) == -1) {
            warn("setuid()");
            _exit(1);
         }
         execve(args_ptr[0], args_ptr, environ);
         warn("execve()");
         _exit(1);

   pamerr:
   fprintf(stderr, "Sorry\n");
   err:
   pam_end(pamh, pam_err);
   exit(1);
}

Я ожидаю раскошелиться на повышенного ребенка и запустить мою новую программу, не спрашивая пароль.

...