Blame view

libmu_auth/pam.c 4.35 KB
1
/* GNU Mailutils -- a suite of utilities for electronic mail
Sergey Poznyakoff authored
2
   Copyright (C) 2002, 2007-2012, 2014-2017 Free Software Foundation,
3
   Inc.
4

5 6 7
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
8
   version 3 of the License, or (at your option) any later version.
9

10
   This library is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.
14

15
   You should have received a copy of the GNU Lesser General
16 17
   Public License along with this library.  If not, see
   <http://www.gnu.org/licenses/>. */
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#ifdef HAVE_SHADOW_H
# include <shadow.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_SECURITY_PAM_APPL_H
# include <security/pam_appl.h>
#endif
#ifdef HAVE_CRYPT_H
# include <crypt.h>
#endif
#include <mailutils/list.h>
43
#include <mailutils/errno.h>
44 45 46
#include <mailutils/iterator.h>
#include <mailutils/mailbox.h>
#include <mailutils/mu_auth.h>
Sergey Poznyakoff authored
47
#include <mailutils/nls.h>
48

49
char *mu_pam_service = PACKAGE;
50 51

#ifdef USE_LIBPAM
52 53 54 55 56 57 58 59
static struct mu_cfg_param mu_pam_param[] = {
  { "service", mu_c_string, &mu_pam_service, 0, NULL,
    N_("Set PAM service name."),
    N_("name") },
  { NULL }
};


60 61 62 63
#define COPY_STRING(s) (s) ? strdup(s) : NULL

static char *_pwd;
static char *_user;
64 65 66 67 68 69 70 71 72 73

#define overwrite_and_free(ptr)			\
  do						\
    {						\
      char *s = ptr;				\
      while (*s)				\
	*s++ = 0;				\
    }						\
  while (0)

74

75 76 77 78
#ifndef PAM_AUTHTOK_RECOVER_ERR
# define PAM_AUTHTOK_RECOVER_ERR PAM_CONV_ERR
#endif

79 80
static int
mu_pam_conv (int num_msg, const struct pam_message **msg,
81
	     struct pam_response **resp, void *appdata_ptr MU_ARG_UNUSED)
82
{
83 84
  int status = PAM_SUCCESS;
  int i;
85 86
  struct pam_response *reply = NULL;

87
  reply = calloc (num_msg, sizeof (*reply));
88 89 90
  if (!reply)
    return PAM_CONV_ERR;

91
  for (i = 0; i < num_msg && status == PAM_SUCCESS; i++)
92
    {
93
      switch (msg[i]->msg_style)
94 95
	{
	case PAM_PROMPT_ECHO_ON:
96 97
	  reply[i].resp_retcode = PAM_SUCCESS;
	  reply[i].resp = COPY_STRING (_user);
98 99 100 101
	  /* PAM frees resp */
	  break;

	case PAM_PROMPT_ECHO_OFF:
102 103 104 105 106 107 108 109
	  if (_pwd)
	    {
	      reply[i].resp_retcode = PAM_SUCCESS;
	      reply[i].resp = COPY_STRING (_pwd);
	      /* PAM frees resp */
	    }
	  else
	    status = PAM_AUTHTOK_RECOVER_ERR;
110 111 112 113
	  break;

	case PAM_TEXT_INFO:
	case PAM_ERROR_MSG:
114 115
	  reply[i].resp_retcode = PAM_SUCCESS;
	  reply[i].resp = NULL;
116 117 118
	  break;
 
	default:
119
	  status = PAM_CONV_ERR;
120 121
	}
    }
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  if (status != PAM_SUCCESS)
    {
      for (i = 0; i < num_msg; i++)
	if (reply[i].resp)
	  {
	    switch (msg[i]->msg_style)
	      {
	      case PAM_PROMPT_ECHO_ON:
	      case PAM_PROMPT_ECHO_OFF:
		overwrite_and_free (reply[i].resp);
		break;
		
	      case PAM_ERROR_MSG:
	      case PAM_TEXT_INFO:
		free (reply[i].resp);
	      }
	  }
      free (reply);
    }
  else
    *resp = reply;
  return status;
144 145 146 147 148
}

static struct pam_conv PAM_conversation = { &mu_pam_conv, NULL };

int
149
mu_authenticate_pam (struct mu_auth_data **return_data MU_ARG_UNUSED,
150
		     const void *key,
151
		     void *func_data MU_ARG_UNUSED,
152 153
		     void *call_data)
{
154
  const struct mu_auth_data *auth_data = key;
155 156 157 158
  char *pass = call_data;
  pam_handle_t *pamh;
  int pamerror;

159
#define PAM_ERROR if (pamerror != PAM_SUCCESS) goto pam_errlab;
160 161

  if (!auth_data)
162
    return EINVAL;
163 164 165
  
  _user = (char *) auth_data->name;
  _pwd = pass;
166
  pamerror = pam_start (mu_pam_service, _user, &PAM_conversation, &pamh);
167 168 169 170 171 172 173 174
  PAM_ERROR;
  pamerror = pam_authenticate (pamh, 0);
  PAM_ERROR;
  pamerror = pam_acct_mgmt (pamh, 0);
  PAM_ERROR;
  pamerror = pam_setcred (pamh, PAM_ESTABLISH_CRED);
 pam_errlab:
  pam_end (pamh, PAM_SUCCESS);
175 176 177 178 179 180 181 182
  switch (pamerror)
    {
    case PAM_SUCCESS:
      return 0;
    case PAM_AUTH_ERR:
      return MU_ERR_AUTH_FAILURE;
    }
  return MU_ERR_FAILURE;
183 184 185
}

#else
186 187
# define mu_pam_param NULL
# define mu_authenticate_pam NULL
188
#endif
189

190
struct mu_auth_module mu_auth_pam_module = {
191 192 193
  .name = "pam",
  .handler = { [mu_auth_authenticate] = mu_authenticate_pam },
  .cfg = mu_pam_param
194 195
};