~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kcheckpass/checkpass_pam.c

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1998 Caldera, Inc.
 
3
 * Copyright (C) 2003 Oswald Buddenhagen <ossi@kde.org>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public
 
16
 * License along with this program; if not, write to the Free
 
17
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
 */
 
19
 
 
20
#include "kcheckpass.h"
 
21
 
 
22
#ifdef HAVE_PAM
 
23
 
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <string.h>
 
27
#include <syslog.h>
 
28
 
 
29
#ifdef HAVE_PAM_PAM_APPL_H
 
30
#include <pam/pam_appl.h>
 
31
#else
 
32
#include <security/pam_appl.h>
 
33
#endif
 
34
 
 
35
struct pam_data {
 
36
  char *(*conv) (ConvRequest, const char *);
 
37
  int abort:1;
 
38
  int classic:1;
 
39
};
 
40
 
 
41
#ifdef PAM_MESSAGE_CONST
 
42
typedef const struct pam_message pam_message_type;
 
43
typedef const void *pam_gi_type;
 
44
#else
 
45
typedef struct pam_message pam_message_type;
 
46
typedef void *pam_gi_type;
 
47
#endif
 
48
 
 
49
static int
 
50
PAM_conv (int num_msg, pam_message_type **msg,
 
51
          struct pam_response **resp,
 
52
          void *appdata_ptr)
 
53
{
 
54
  int count;
 
55
  struct pam_response *repl;
 
56
  struct pam_data *pd = (struct pam_data *)appdata_ptr;
 
57
 
 
58
  if (!(repl = calloc(num_msg, sizeof(struct pam_response))))
 
59
    return PAM_CONV_ERR;
 
60
 
 
61
  for (count = 0; count < num_msg; count++)
 
62
    switch (msg[count]->msg_style) {
 
63
    case PAM_TEXT_INFO:
 
64
      pd->conv(ConvPutInfo, msg[count]->msg);
 
65
      break;
 
66
    case PAM_ERROR_MSG:
 
67
      pd->conv(ConvPutError, msg[count]->msg);
 
68
      break;
 
69
    default:
 
70
      switch (msg[count]->msg_style) {
 
71
      case PAM_PROMPT_ECHO_ON:
 
72
        repl[count].resp = pd->conv(ConvGetNormal, msg[count]->msg);
 
73
        break;
 
74
      case PAM_PROMPT_ECHO_OFF:
 
75
        repl[count].resp =
 
76
            pd->conv(ConvGetHidden, pd->classic ? 0 : msg[count]->msg);
 
77
        break;
 
78
#ifdef PAM_BINARY_PROMPT
 
79
      case PAM_BINARY_PROMPT:
 
80
        repl[count].resp = pd->conv(ConvGetBinary, msg[count]->msg);
 
81
        break;
 
82
#endif
 
83
      default:
 
84
        /* Must be an error of some sort... */
 
85
        goto conv_err;
 
86
      }
 
87
      if (!repl[count].resp) {
 
88
        pd->abort = 1;
 
89
        goto conv_err;
 
90
      }
 
91
      repl[count].resp_retcode = PAM_SUCCESS;
 
92
      break;
 
93
    }
 
94
  *resp = repl;
 
95
  return PAM_SUCCESS;
 
96
 
 
97
 conv_err:
 
98
  for (; count >= 0; count--)
 
99
    if (repl[count].resp)
 
100
      switch (msg[count]->msg_style) {
 
101
      case PAM_PROMPT_ECHO_OFF:
 
102
        dispose(repl[count].resp);
 
103
        break;
 
104
#ifdef PAM_BINARY_PROMPT
 
105
      case PAM_BINARY_PROMPT: /* handle differently? */
 
106
#endif
 
107
      case PAM_PROMPT_ECHO_ON:
 
108
        free(repl[count].resp);
 
109
        break;
 
110
      }
 
111
  free(repl);
 
112
  return PAM_CONV_ERR;
 
113
}
 
114
 
 
115
static struct pam_data PAM_data;
 
116
 
 
117
static struct pam_conv PAM_conversation = {
 
118
  &PAM_conv,
 
119
  &PAM_data
 
120
};
 
121
 
 
122
#ifdef PAM_FAIL_DELAY
 
123
static void
 
124
fail_delay(int retval ATTR_UNUSED, unsigned usec_delay ATTR_UNUSED, 
 
125
           void *appdata_ptr ATTR_UNUSED)
 
126
{}
 
127
#endif
 
128
 
 
129
 
 
130
AuthReturn Authenticate(const char *caller, const char *method,
 
131
        const char *user, char *(*conv) (ConvRequest, const char *))
 
132
{
 
133
  const char    *tty;
 
134
  pam_handle_t  *pamh;
 
135
  pam_gi_type   pam_item;
 
136
  const char    *pam_service;
 
137
  char          pservb[64];
 
138
  int           pam_error;
 
139
 
 
140
  openlog("kcheckpass", LOG_PID, LOG_AUTH);
 
141
 
 
142
  PAM_data.conv = conv;
 
143
  if (strcmp(method, "classic")) {
 
144
    sprintf(pservb, "%.31s-%.31s", caller, method);
 
145
    pam_service = pservb;
 
146
  } else {
 
147
    /* PAM_data.classic = 1; */
 
148
    pam_service = caller;
 
149
  }
 
150
  pam_error = pam_start(pam_service, user, &PAM_conversation, &pamh);
 
151
  if (pam_error != PAM_SUCCESS)
 
152
    return AuthError;
 
153
 
 
154
  tty = ttyname(0);
 
155
  if (!tty)
 
156
    tty = getenv ("DISPLAY");
 
157
 
 
158
  pam_error = pam_set_item (pamh, PAM_TTY, tty);
 
159
  if (pam_error != PAM_SUCCESS) {
 
160
    pam_end(pamh, pam_error);
 
161
    return AuthError;
 
162
  }
 
163
 
 
164
# ifdef PAM_FAIL_DELAY
 
165
  pam_set_item (pamh, PAM_FAIL_DELAY, (void *)fail_delay);
 
166
# endif
 
167
 
 
168
  pam_error = pam_authenticate(pamh, 0);
 
169
  if (pam_error != PAM_SUCCESS) {
 
170
    if (PAM_data.abort) {
 
171
      pam_end(pamh, PAM_SUCCESS);
 
172
      return AuthAbort;
 
173
    }
 
174
    pam_end(pamh, pam_error);
 
175
    switch (pam_error) {
 
176
      case PAM_USER_UNKNOWN:
 
177
      case PAM_AUTH_ERR:
 
178
      case PAM_MAXTRIES: /* should handle this better ... */
 
179
      case PAM_AUTHINFO_UNAVAIL: /* returned for unknown users ... bogus */
 
180
        return AuthBad;
 
181
      default:
 
182
        return AuthError;
 
183
    }
 
184
  }
 
185
 
 
186
  /* just in case some module is stupid enough to ignore a preset PAM_USER */
 
187
  pam_error = pam_get_item (pamh, PAM_USER, &pam_item);
 
188
  if (pam_error != PAM_SUCCESS) {
 
189
    pam_end(pamh, pam_error);
 
190
    return AuthError;
 
191
  }
 
192
  if (strcmp((const char *)pam_item, user)) {
 
193
    pam_end(pamh, PAM_SUCCESS); /* maybe use PAM_AUTH_ERR? */
 
194
    return AuthBad;
 
195
  }
 
196
 
 
197
  pam_error = pam_setcred(pamh, PAM_REFRESH_CRED);
 
198
  /* ignore errors on refresh credentials. If this did not work we use the old ones. */
 
199
 
 
200
  pam_end(pamh, PAM_SUCCESS);
 
201
  return AuthOk;
 
202
}
 
203
 
 
204
#endif