(root)/
Linux-PAM-1.5.3/
examples/
tty_conv.c
       1  /* PlanC (hubenchang0515@outlook.com) -- an example application
       2   * that implements a custom conversation */
       3  
       4  #include <stdio.h>
       5  #include <stdlib.h>
       6  #include <string.h>
       7  #include <errno.h>
       8  #include <unistd.h>
       9  #include <termio.h>
      10  #include <security/pam_appl.h>
      11  
      12  /***************************************
      13   * @brief echo off/on
      14   * @param[in] fd file descriptor
      15   * @param[in] off 1 - echo off,0 - echo on
      16   ***************************************/
      17  static void echoOff(int fd, int off)
      18  {
      19      struct termio tty;
      20      if (ioctl(fd, TCGETA, &tty) < 0)
      21      {
      22          fprintf(stderr, "TCGETA failed: %s\n", strerror(errno));
      23          return;
      24      }
      25  
      26      if (off)
      27      {
      28          tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
      29          if (ioctl(fd, TCSETAF, &tty) < 0)
      30          {
      31              fprintf(stderr, "TCSETAF failed: %s\n", strerror(errno));
      32          }
      33      }
      34      else
      35      {
      36          tty.c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL);
      37          if (ioctl(fd, TCSETAW, &tty) < 0)
      38          {
      39              fprintf(stderr, "TCSETAW failed: %s\n", strerror(errno));
      40          }
      41      }
      42  }
      43  
      44  /***************************************
      45   * @brief echo off stdin
      46   ***************************************/
      47  static void echoOffStdin(void)
      48  {
      49      echoOff(fileno(stdin), 1);
      50  }
      51  
      52  /***************************************
      53   * @brief echo on stdin
      54   ***************************************/
      55  static void echoOnStdin(void)
      56  {
      57      echoOff(fileno(stdin), 0);
      58  }
      59  
      60  /***************************************
      61   * @brief read a line input
      62   * @return the input string
      63   ***************************************/
      64  static char *readline(void)
      65  {
      66      char input[PAM_MAX_RESP_SIZE];
      67      int i;
      68  
      69      flockfile(stdin);
      70      for (i = 0; i < PAM_MAX_RESP_SIZE; i++)
      71      {
      72          int ch = getchar_unlocked();
      73          if (ch == '\n' || ch == '\r' ||ch == EOF)
      74              break;
      75          input[i] = ch;
      76      }
      77      funlockfile(stdin);
      78      input[i] = '\0';
      79  
      80      return (strdup(input));
      81  }
      82  
      83  /**************************************************
      84   * @brief callback of PAM conversation
      85   * @param[in] num_msg the count of message
      86   * @param[in] msg PAM message
      87   * @param[out] resp our response
      88   * @param[in] appdata_ptr custom data passed by struct pam_conv.appdata_ptr
      89   * @return state
      90   **************************************************/
      91  static int conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
      92  {
      93      (void)(appdata_ptr);
      94      int i;
      95  
      96      /* check the count of message */
      97      if (num_msg <= 0 || num_msg >= PAM_MAX_MSG_SIZE)
      98      {
      99          fprintf(stderr, "invalid num_msg(%d)\n", num_msg);
     100          return PAM_CONV_ERR;
     101      }
     102  
     103      /* alloc memory for response */
     104      if ((resp[0] = malloc(num_msg * sizeof(struct pam_response))) == NULL)
     105      {
     106          fprintf(stderr, "bad alloc\n");
     107          return PAM_BUF_ERR;
     108      }
     109  
     110      /* response for message */
     111      for (i = 0; i < num_msg; i++)
     112      {
     113          const struct pam_message *m = *msg + i;
     114          struct pam_response *r = *resp + i;
     115          r->resp_retcode = 0;    /* currently un-used, zero expected */
     116          switch (m->msg_style)
     117          {
     118          case PAM_PROMPT_ECHO_OFF:   /* get the input with echo off, like the password */
     119              printf("%s", m->msg);
     120              echoOffStdin();
     121              r->resp = readline();
     122              echoOnStdin();
     123              printf("\n");
     124              break;
     125  
     126          case PAM_PROMPT_ECHO_ON:    /* get the input with echo on, like the username */
     127              printf("%s", m->msg);
     128              r->resp = readline();
     129              break;
     130  
     131          case PAM_TEXT_INFO:         /* normal info */
     132              printf("%s\n", m->msg);
     133              break;
     134  
     135          case PAM_ERROR_MSG:         /* error info */
     136              fprintf(stderr, "%s\n", m->msg);
     137              break;
     138  
     139          default:
     140              fprintf(stderr, "unexpected msg_style: %d\n", m->msg_style);
     141              break;
     142          }
     143      }
     144      return PAM_SUCCESS;
     145  }
     146  
     147  int main(void)
     148  {
     149      struct pam_conv pam_conv = {conversation, NULL};
     150      pam_handle_t *pamh;
     151  
     152      /* echo on while exist, like Ctrl+C on input password */
     153      atexit(echoOnStdin);
     154  
     155      if (PAM_SUCCESS != pam_start("login", NULL, &pam_conv, &pamh))
     156      {
     157          fprintf(stderr, "pam_start failed\n");
     158          return EXIT_FAILURE;
     159      }
     160  
     161      if (PAM_SUCCESS != pam_authenticate(pamh, 0))
     162      {
     163          fprintf(stderr, "pam_authenticate failed\n");
     164          pam_end(pamh, 0);
     165          return EXIT_FAILURE;
     166      }
     167  
     168      if (PAM_SUCCESS != pam_acct_mgmt(pamh, 0))
     169      {
     170          fprintf(stderr, "pam_acct_mgmt failed\n");
     171          pam_end(pamh, 0);
     172          return EXIT_FAILURE;
     173      }
     174  
     175      pam_end(pamh, 0);
     176      return EXIT_SUCCESS;
     177  }