source: openpam/trunk/lib/libpam/pam_get_authtok.c @ 913

Last change on this file since 913 was 913, checked in by Dag-Erling Smørgrav, 4 years ago

Newer versions of clang take nonnull annotations into account not only
when compiling code that calls the function, but also when compiling the
function itself. This means that NULL checks in the function trigger
condition-always-false warnings. We have a choice between disabling these
warnings, removing the nonnull annotations, or removing the NULL checks.
We prefer to keep the annotations and warnings and remove the checks. In
all cases, passing NULL to the function in question will result in a
segmentation fault, which is often easier to debug than an error return,
especially when most of these checks were for the PAM handle, which can only
be NULL if the caller ignored an error return from pam_start().

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.7 KB
Line 
1/*-
2 * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
3 * Copyright (c) 2004-2017 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 913 2017-01-21 15:11:12Z 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#include "openpam_strlset.h"
52
53static const char authtok_prompt[] = "Password:";
54static const char authtok_prompt_remote[] = "Password for %u@%h:";
55static const char oldauthtok_prompt[] = "Old Password:";
56static const char newauthtok_prompt[] = "New Password:";
57
58/*
59 * OpenPAM extension
60 *
61 * Retrieve authentication token
62 */
63
64int
65pam_get_authtok(pam_handle_t *pamh,
66        int item,
67        const char **authtok,
68        const char *prompt)
69{
70        char prompt_buf[1024];
71        size_t prompt_size;
72        const void *oldauthtok, *prevauthtok, *promptp;
73        const char *prompt_option, *default_prompt;
74        const void *lhost, *rhost;
75        char *resp, *resp2;
76        int pitem, r, style, twice;
77
78        ENTER();
79        *authtok = NULL;
80        twice = 0;
81        switch (item) {
82        case PAM_AUTHTOK:
83                pitem = PAM_AUTHTOK_PROMPT;
84                prompt_option = "authtok_prompt";
85                default_prompt = authtok_prompt;
86                r = pam_get_item(pamh, PAM_RHOST, &rhost);
87                if (r == PAM_SUCCESS && rhost != NULL) {
88                        r = pam_get_item(pamh, PAM_HOST, &lhost);
89                        if (r == PAM_SUCCESS && lhost != NULL) {
90                                if (strcmp(rhost, lhost) != 0)
91                                        default_prompt = authtok_prompt_remote;
92                        }
93                }
94                r = pam_get_item(pamh, PAM_OLDAUTHTOK, &oldauthtok);
95                if (r == PAM_SUCCESS && oldauthtok != NULL) {
96                        default_prompt = newauthtok_prompt;
97                        twice = 1;
98                }
99                break;
100        case PAM_OLDAUTHTOK:
101                pitem = PAM_OLDAUTHTOK_PROMPT;
102                prompt_option = "oldauthtok_prompt";
103                default_prompt = oldauthtok_prompt;
104                twice = 0;
105                break;
106        default:
107                RETURNC(PAM_SYMBOL_ERR);
108        }
109        if (openpam_get_option(pamh, "try_first_pass") ||
110            openpam_get_option(pamh, "use_first_pass")) {
111                r = pam_get_item(pamh, item, &prevauthtok);
112                if (r == PAM_SUCCESS && prevauthtok != NULL) {
113                        *authtok = prevauthtok;
114                        RETURNC(PAM_SUCCESS);
115                } else if (openpam_get_option(pamh, "use_first_pass")) {
116                        RETURNC(r == PAM_SUCCESS ? PAM_AUTH_ERR : r);
117                }
118        }
119        /* pam policy overrides the module's choice */
120        if ((promptp = openpam_get_option(pamh, prompt_option)) != NULL)
121                prompt = promptp;
122        /* no prompt provided, see if there is one tucked away somewhere */
123        if (prompt == NULL) {
124                r = pam_get_item(pamh, pitem, &promptp);
125                if (r == PAM_SUCCESS && promptp != NULL)
126                        prompt = promptp;
127        }
128        /* fall back to hardcoded default */
129        if (prompt == NULL)
130                prompt = default_prompt;
131        /* expand */
132        prompt_size = sizeof prompt_buf;
133        r = openpam_subst(pamh, prompt_buf, &prompt_size, prompt);
134        if (r == PAM_SUCCESS && prompt_size <= sizeof prompt_buf)
135                prompt = prompt_buf;
136        style = openpam_get_option(pamh, "echo_pass") ?
137            PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF;
138        r = pam_prompt(pamh, style, &resp, "%s", prompt);
139        if (r != PAM_SUCCESS)
140                RETURNC(r);
141        if (twice) {
142                r = pam_prompt(pamh, style, &resp2, "Retype %s", prompt);
143                if (r != PAM_SUCCESS) {
144                        strlset(resp, 0, PAM_MAX_RESP_SIZE);
145                        FREE(resp);
146                        RETURNC(r);
147                }
148                if (strcmp(resp, resp2) != 0) {
149                        strlset(resp, 0, PAM_MAX_RESP_SIZE);
150                        FREE(resp);
151                }
152                strlset(resp2, 0, PAM_MAX_RESP_SIZE);
153                FREE(resp2);
154        }
155        if (resp == NULL)
156                RETURNC(PAM_TRY_AGAIN);
157        r = pam_set_item(pamh, item, resp);
158        strlset(resp, 0, PAM_MAX_RESP_SIZE);
159        FREE(resp);
160        if (r != PAM_SUCCESS)
161                RETURNC(r);
162        r = pam_get_item(pamh, item, (const void **)authtok);
163        RETURNC(r);
164}
165
166/*
167 * Error codes:
168 *
169 *      =pam_get_item
170 *      =pam_prompt
171 *      =pam_set_item
172 *      !PAM_SYMBOL_ERR
173 *      PAM_TRY_AGAIN
174 */
175
176/**
177 * The =pam_get_authtok function either prompts the user for an
178 * authentication token or retrieves a cached authentication token,
179 * depending on circumstances.
180 * Either way, a pointer to the authentication token is stored in the
181 * location pointed to by the =authtok argument, and the corresponding PAM
182 * item is updated.
183 *
184 * The =item argument must have one of the following values:
185 *
186 *      =PAM_AUTHTOK:
187 *              Returns the current authentication token, or the new token
188 *              when changing authentication tokens.
189 *      =PAM_OLDAUTHTOK:
190 *              Returns the previous authentication token when changing
191 *              authentication tokens.
192 *
193 * The =prompt argument specifies a prompt to use if no token is cached.
194 * If it is =NULL, the =PAM_AUTHTOK_PROMPT or =PAM_OLDAUTHTOK_PROMPT item,
195 * as appropriate, will be used.
196 * If that item is also =NULL, a hardcoded default prompt will be used.
197 * Additionally, when =pam_get_authtok is called from a service module,
198 * the prompt may be affected by module options as described below.
199 * The prompt is then expanded using =openpam_subst before it is passed to
200 * the conversation function.
201 *
202 * If =item is set to =PAM_AUTHTOK and there is a non-null =PAM_OLDAUTHTOK
203 * item, =pam_get_authtok will ask the user to confirm the new token by
204 * retyping it.
205 * If there is a mismatch, =pam_get_authtok will return =PAM_TRY_AGAIN.
206 *
207 * MODULE OPTIONS
208 *
209 * When called by a service module, =pam_get_authtok will recognize the
210 * following module options:
211 *
212 *      ;authtok_prompt:
213 *              Prompt to use when =item is set to =PAM_AUTHTOK.
214 *              This option overrides both the =prompt argument and the
215 *              =PAM_AUTHTOK_PROMPT item.
216 *      ;echo_pass:
217 *              If the application's conversation function allows it, this
218 *              lets the user see what they are typing.
219 *              This should only be used for non-reusable authentication
220 *              tokens.
221 *      ;oldauthtok_prompt:
222 *              Prompt to use when =item is set to =PAM_OLDAUTHTOK.
223 *              This option overrides both the =prompt argument and the
224 *              =PAM_OLDAUTHTOK_PROMPT item.
225 *      ;try_first_pass:
226 *              If the requested item is non-null, return it without
227 *              prompting the user.
228 *              Typically, the service module will verify the token, and
229 *              if it does not match, clear the item before calling
230 *              =pam_get_authtok a second time.
231 *      ;use_first_pass:
232 *              Do not prompt the user at all; just return the cached
233 *              value, or =PAM_AUTH_ERR if there is none.
234 *
235 * >pam_conv
236 * >pam_get_item
237 * >pam_get_user
238 * >openpam_get_option
239 * >openpam_subst
240 */
Note: See TracBrowser for help on using the repository browser.