2 * Copyright (C) 1998 Caldera, Inc.
3 * Copyright (C) 2003 Oswald Buddenhagen <ossi@kde.org>
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.
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.
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.
20 #include "kcheckpass.h"
29 #ifdef HAVE_PAM_PAM_APPL_H
30 #include <pam/pam_appl.h>
32 #include <security/pam_appl.h>
36 char *(*conv
) (ConvRequest
, const char *);
41 #ifdef PAM_MESSAGE_NONCONST
42 typedef struct pam_message pam_message_type
;
43 typedef void *pam_gi_type
;
45 typedef const struct pam_message pam_message_type
;
46 typedef const void *pam_gi_type
;
50 PAM_conv (int num_msg
, pam_message_type
**msg
,
51 struct pam_response
**resp
,
55 struct pam_response
*repl
;
56 struct pam_data
*pd
= (struct pam_data
*)appdata_ptr
;
58 if (!(repl
= calloc(num_msg
, sizeof(struct pam_response
))))
61 for (count
= 0; count
< num_msg
; count
++)
62 switch (msg
[count
]->msg_style
) {
64 pd
->conv(ConvPutInfo
, msg
[count
]->msg
);
67 pd
->conv(ConvPutError
, msg
[count
]->msg
);
70 switch (msg
[count
]->msg_style
) {
71 case PAM_PROMPT_ECHO_ON
:
72 repl
[count
].resp
= pd
->conv(ConvGetNormal
, msg
[count
]->msg
);
74 case PAM_PROMPT_ECHO_OFF
:
76 pd
->conv(ConvGetHidden
, pd
->classic
? 0 : msg
[count
]->msg
);
78 #ifdef PAM_BINARY_PROMPT
79 case PAM_BINARY_PROMPT
:
80 repl
[count
].resp
= pd
->conv(ConvGetBinary
, msg
[count
]->msg
);
84 /* Must be an error of some sort... */
87 if (!repl
[count
].resp
) {
91 repl
[count
].resp_retcode
= PAM_SUCCESS
;
98 for (; count
>= 0; count
--)
100 switch (msg
[count
]->msg_style
) {
101 case PAM_PROMPT_ECHO_OFF
:
102 dispose(repl
[count
].resp
);
104 #ifdef PAM_BINARY_PROMPT
105 case PAM_BINARY_PROMPT
: /* handle differently? */
107 case PAM_PROMPT_ECHO_ON
:
108 free(repl
[count
].resp
);
115 static struct pam_data PAM_data
;
117 static struct pam_conv PAM_conversation
= {
122 #ifdef PAM_FAIL_DELAY
124 fail_delay(int retval ATTR_UNUSED
, unsigned usec_delay ATTR_UNUSED
,
125 void *appdata_ptr ATTR_UNUSED
)
130 AuthReturn
Authenticate(const char *caller
, const char *method
,
131 const char *user
, char *(*conv
) (ConvRequest
, const char *))
135 pam_gi_type pam_item
;
136 const char *pam_service
;
140 openlog("kcheckpass", LOG_PID
, LOG_AUTH
);
142 PAM_data
.conv
= conv
;
143 if (strcmp(method
, "classic")) {
144 sprintf(pservb
, "%.31s-%.31s", caller
, method
);
145 pam_service
= pservb
;
147 /* PAM_data.classic = 1; */
148 pam_service
= caller
;
150 pam_error
= pam_start(pam_service
, user
, &PAM_conversation
, &pamh
);
151 if (pam_error
!= PAM_SUCCESS
)
156 tty
= getenv ("DISPLAY");
158 pam_error
= pam_set_item (pamh
, PAM_TTY
, tty
);
159 if (pam_error
!= PAM_SUCCESS
) {
160 pam_end(pamh
, pam_error
);
164 # ifdef PAM_FAIL_DELAY
165 pam_set_item (pamh
, PAM_FAIL_DELAY
, (void *)fail_delay
);
168 pam_error
= pam_authenticate(pamh
, 0);
169 if (pam_error
!= PAM_SUCCESS
) {
170 if (PAM_data
.abort
) {
171 pam_end(pamh
, PAM_SUCCESS
);
174 pam_end(pamh
, pam_error
);
176 case PAM_USER_UNKNOWN
:
178 case PAM_MAXTRIES
: /* should handle this better ... */
179 case PAM_AUTHINFO_UNAVAIL
: /* returned for unknown users ... bogus */
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
);
192 if (strcmp((const char *)pam_item
, user
)) {
193 pam_end(pamh
, PAM_SUCCESS
); /* maybe use PAM_AUTH_ERR? */
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. */
200 pam_end(pamh
, PAM_SUCCESS
);