source: openpam/trunk/lib/pam_get_authtok.c @ 594

Last change on this file since 594 was 510, checked in by Dag-Erling Smørgrav, 10 years ago

Use a different default prompt if PAM_RHOST != PAM_HOST.

  • Property svn:keywords set to Id
File size: 6.5 KB
Line 
1/*-
2 * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
3 * Copyright (c) 2004-2011 Dag-Erling Smørgrav
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by ThinkSec AS and
7 * Network Associates Laboratories, the Security Research Division of
8 * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
9 * ("CBOSS"), as part of the DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote
20 *    products derived from this software without specific prior written
21 *    permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * $Id: pam_get_authtok.c 510 2011-12-31 13:14:23Z des $
36 */
37
38#ifdef HAVE_CONFIG_H
39# include "config.h"
40#endif
41
42#include <sys/param.h>
43
44#include <stdlib.h>
45#include <string.h>
46
47#include <security/pam_appl.h>
48#include <security/openpam.h>
49
50#include "openpam_impl.h"
51
52static const char authtok_prompt[] = "Password:";
53static const char authtok_prompt_remote[] = "Password for %u@%h:";
54static const char oldauthtok_prompt[] = "Old Password:";
55static const char newauthtok_prompt[] = "New Password:";
56
57/*
58 * OpenPAM extension
59 *
60 * Retrieve authentication token
61 */
62
63int
64pam_get_authtok(pam_handle_t *pamh,
65        int item,
66        const char **authtok,
67        const char *prompt)
68{
69        char prompt_buf[1024];
70        size_t prompt_size;
71        const void *oldauthtok, *prevauthtok, *promptp;
72        const char *prompt_option, *default_prompt;
73        const void *lhost, *rhost;
74        char *resp, *resp2;
75        int pitem, r, style, twice;
76
77        ENTER();
78        if (pamh == NULL || authtok == NULL)
79                RETURNC(PAM_SYSTEM_ERR);
80        *authtok = NULL;
81        twice = 0;
82        switch (item) {
83        case PAM_AUTHTOK:
84                pitem = PAM_AUTHTOK_PROMPT;
85                prompt_option = "authtok_prompt";
86                default_prompt = authtok_prompt;
87                r = pam_get_item(pamh, PAM_RHOST, &rhost);
88                if (r == PAM_SUCCESS && rhost != NULL) {
89                        r = pam_get_item(pamh, PAM_HOST, &lhost);
90                        if (r == PAM_SUCCESS && lhost != NULL) {
91                                if (strcmp(rhost, lhost) != 0)
92                                        default_prompt = authtok_prompt_remote;
93                        }
94                }
95                r = pam_get_item(pamh, PAM_OLDAUTHTOK, &oldauthtok);
96                if (r == PAM_SUCCESS && oldauthtok != NULL) {
97                        default_prompt = newauthtok_prompt;
98                        twice = 1;
99                }
100                break;
101        case PAM_OLDAUTHTOK:
102                pitem = PAM_OLDAUTHTOK_PROMPT;
103                prompt_option = "oldauthtok_prompt";
104                default_prompt = oldauthtok_prompt;
105                twice = 0;
106                break;
107        default:
108                RETURNC(PAM_SYMBOL_ERR);
109        }
110        if (openpam_get_option(pamh, "try_first_pass") ||
111            openpam_get_option(pamh, "use_first_pass")) {
112                r = pam_get_item(pamh, item, &prevauthtok);
113                if (r == PAM_SUCCESS && prevauthtok != NULL) {
114                        *authtok = prevauthtok;
115                        RETURNC(PAM_SUCCESS);
116                }
117                else if (openpam_get_option(pamh, "use_first_pass"))
118                        RETURNC(r == PAM_SUCCESS ? PAM_AUTH_ERR : r);
119        }
120        /* pam policy overrides the module's choice */
121        if ((promptp = openpam_get_option(pamh, prompt_option)) != NULL)
122                prompt = promptp;
123        /* no prompt provided, see if there is one tucked away somewhere */
124        if (prompt == NULL)
125                if (pam_get_item(pamh, pitem, &promptp) && promptp != NULL)
126                        prompt = promptp;
127        /* fall back to hardcoded default */
128        if (prompt == NULL)
129                prompt = default_prompt;
130        /* expand */
131        prompt_size = sizeof prompt_buf;
132        r = openpam_subst(pamh, prompt_buf, &prompt_size, prompt);
133        if (r == PAM_SUCCESS && prompt_size <= sizeof prompt_buf)
134                prompt = prompt_buf;
135        style = openpam_get_option(pamh, "echo_pass") ?
136            PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF;
137        r = pam_prompt(pamh, style, &resp, "%s", prompt);
138        if (r != PAM_SUCCESS)
139                RETURNC(r);
140        if (twice) {
141                r = pam_prompt(pamh, style, &resp2, "Retype %s", prompt);
142                if (r != PAM_SUCCESS) {
143                        FREE(resp);
144                        RETURNC(r);
145                }
146                if (strcmp(resp, resp2) != 0)
147                        FREE(resp);
148                FREE(resp2);
149        }
150        if (resp == NULL)
151                RETURNC(PAM_TRY_AGAIN);
152        r = pam_set_item(pamh, item, resp);
153        FREE(resp);
154        if (r != PAM_SUCCESS)
155                RETURNC(r);
156        r = pam_get_item(pamh, item, (const void **)authtok);
157        RETURNC(r);
158}
159
160/*
161 * Error codes:
162 *
163 *      =pam_get_item
164 *      =pam_prompt
165 *      =pam_set_item
166 *      !PAM_SYMBOL_ERR
167 *      PAM_TRY_AGAIN
168 */
169
170/**
171 * The =pam_get_authtok function returns the cached authentication token,
172 * or prompts the user if no token is currently cached.
173 * Either way, a pointer to the authentication token is stored in the
174 * location pointed to by the =authtok argument.
175 *
176 * The =item argument must have one of the following values:
177 *
178 *      =PAM_AUTHTOK:
179 *              Returns the current authentication token, or the new token
180 *              when changing authentication tokens.
181 *      =PAM_OLDAUTHTOK:
182 *              Returns the previous authentication token when changing
183 *              authentication tokens.
184 *
185 * The =prompt argument specifies a prompt to use if no token is cached.
186 * If it is =NULL, the =PAM_AUTHTOK_PROMPT or =PAM_OLDAUTHTOK_PROMPT item,
187 * as appropriate, will be used.
188 * If that item is also =NULL, a hardcoded default prompt will be used.
189 * Either way, the prompt is expanded using =openpam_subst before it is
190 * passed to the conversation function.
191 *
192 * If =pam_get_authtok is called from a module and the ;authtok_prompt /
193 * ;oldauthtok_prompt option is set in the policy file, the value of that
194 * option takes precedence over both the =prompt argument and the
195 * =PAM_AUTHTOK_PROMPT / =PAM_OLDAUTHTOK_PROMPT item.
196 *
197 * If =item is set to =PAM_AUTHTOK and there is a non-null =PAM_OLDAUTHTOK
198 * item, =pam_get_authtok will ask the user to confirm the new token by
199 * retyping it.
200 * If there is a mismatch, =pam_get_authtok will return =PAM_TRY_AGAIN.
201 *
202 * >pam_get_item
203 * >pam_get_user
204 * >openpam_subst
205 */
Note: See TracBrowser for help on using the repository browser.