1 /* auth-pam.c -- PAM authentification routine for vlock,
2 * the VT locking program for linux
4 * This program is copyright (C) 2007 Frank Benkstein, and is free
5 * software which is freely distributable under the terms of the
6 * GNU General Public License version 2, included as the file COPYING in this
7 * distribution. It is NOT public domain software, and any
8 * redistribution not permitted by the GNU General Public License is
9 * expressly forbidden without prior written permission from
13 * The conversation function (conversation) was inspired by/copied from
14 * openpam's openpam_ttyconv.c:
16 * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. The name of the author may not be used to endorse or promote
27 * products derived from this software without specific prior written
30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 #include <security/pam_appl.h>
55 GQuark
vlock_auth_error_quark(void)
57 return g_quark_from_static_string("vlock-auth-pam-error-quark");
60 struct conversation_data
{
62 struct timespec
*timeout
;
65 /* PAM conversation function. Assumes that a pointer to struct
66 * conversation_data is passed as the as appdata_ptr argument. In case of a
67 * normal error conversation_data's error field is set accordingly and
68 * PAM_CONV_ERR is returned while in case of a memory allocation error
69 * PAM_BUF_ERR is returned and the error field is left untouched. On success
70 * PAM_SUCCESS is returned.
72 static int conversation(int num_msg
, const struct pam_message
**msg
, struct
73 pam_response
**resp
, void *appdata_ptr
)
75 struct pam_response
*aresp
;
76 struct conversation_data
*conv_data
= appdata_ptr
;
78 g_return_val_if_fail(conv_data
->error
== NULL
, PAM_CONV_ERR
);
79 g_return_val_if_fail(num_msg
> 0 && num_msg
< PAM_MAX_NUM_MSG
, PAM_CONV_ERR
);
81 if ((aresp
= calloc((size_t) num_msg
, sizeof *aresp
)) == NULL
)
84 for (int i
= 0; i
< num_msg
; i
++) {
85 switch (msg
[i
]->msg_style
) {
86 case PAM_PROMPT_ECHO_OFF
:
87 aresp
[i
].resp
= prompt_echo_off(msg
[i
]->msg
, conv_data
->timeout
, &conv_data
->error
);
88 if (aresp
[i
].resp
== NULL
)
91 case PAM_PROMPT_ECHO_ON
:
92 aresp
[i
].resp
= prompt(msg
[i
]->msg
, conv_data
->timeout
, &conv_data
->error
);
93 if (aresp
[i
].resp
== NULL
)
99 size_t msg_len
= strlen(msg
[i
]->msg
);
100 (void) fputs(msg
[i
]->msg
, stderr
);
101 if (msg_len
> 0 && msg
[i
]->msg
[msg_len
- 1] != '\n')
102 (void) fputc('\n', stderr
);
114 for (int i
= 0; i
< num_msg
; ++i
) {
115 if (aresp
[i
].resp
!= NULL
) {
116 memset(aresp
[i
].resp
, 0, strlen(aresp
[i
].resp
));
121 memset(aresp
, 0, num_msg
* sizeof *aresp
);
125 g_warn_if_fail(conv_data
->error
!= NULL
, PAM_CONV_ERR
);
130 bool auth(const char *user
, struct timespec
*timeout
, GError
**error
)
136 struct conversation_data conv_data
= {
140 struct pam_conv pamc
= {
141 .conv
= conversation
,
142 .appdata_ptr
= &conv_data
,
145 g_return_val_if_fail(error
== NULL
|| *error
== NULL
, false);
148 pam_status
= pam_start("vlock", user
, &pamc
, &pamh
);
150 if (pam_status
!= PAM_SUCCESS
) {
151 g_propagate_error(error
,
154 VLOCK_AUTH_ERROR_FAILED
,
155 pam_strerror(pamh
, pam_status
)));
159 /* get the name of stdin's tty device, if any */
160 pam_tty
= ttyname(STDIN_FILENO
);
163 if (pam_tty
!= NULL
) {
164 pam_status
= pam_set_item(pamh
, PAM_TTY
, pam_tty
);
166 if (pam_status
!= PAM_SUCCESS
) {
167 g_propagate_error(error
,
170 VLOCK_AUTH_ERROR_FAILED
,
171 pam_strerror(pamh
, pam_status
)));
176 /* put the username before the password prompt */
177 fprintf(stderr
, "%s's ", user
);
180 /* authenticate the user */
181 pam_status
= pam_authenticate(pamh
, 0);
183 if (pam_status
== PAM_CONV_ERR
) {
184 g_assert(conv_data
.error
!= NULL
);
185 g_propagate_error(error
, conv_data
.error
);
186 } else if (pam_status
!= PAM_SUCCESS
) {
187 g_assert(conv_data
.error
== NULL
);
189 g_propagate_error(error
,
192 VLOCK_AUTH_ERROR_FAILED
,
193 pam_strerror(pamh
, pam_status
)));
198 pam_end_status
= pam_end(pamh
, pam_status
);
200 if (pam_end_status
!= PAM_SUCCESS
&& error
!= NULL
&& *error
== NULL
)) {
201 g_propagate_error(error
,
204 VLOCK_AUTH_ERROR_FAILED
,
205 pam_strerror(pamh
, pam_status
)));
208 return (pam_end_status
== PAM_SUCCESS
&& pam_status
== PAM_SUCCESS
);