1/*	$NetBSD: openpam_subst.c,v 1.4 2023/06/30 21:46:21 christos Exp $	*/
2
3/*-
4 * Copyright (c) 2011-2023 Dag-Erling Sm��rgrav
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote
16 *    products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifdef HAVE_CONFIG_H
33# include "config.h"
34#endif
35
36#include <sys/cdefs.h>
37__RCSID("$NetBSD: openpam_subst.c,v 1.4 2023/06/30 21:46:21 christos Exp $");
38
39#include <security/pam_appl.h>
40
41#include "openpam_impl.h"
42
43#define subst_char(ch) do {			\
44	char ch_ = (ch);			\
45	if (buf && len < *bufsize)		\
46		*buf++ = ch_;			\
47	++len;					\
48} while (/*CONSTCOND*/0)
49
50#define subst_string(s) do {			\
51	const char *s_ = (s);			\
52	while (*s_)				\
53		subst_char(*s_++);		\
54} while (/*CONSTCOND*/0)
55
56#define subst_item(i) do {			\
57	int i_ = (i);				\
58	const void *p_;				\
59	ret = pam_get_item(pamh, i_, &p_);	\
60	if (ret == PAM_SUCCESS && p_ != NULL)	\
61		subst_string(p_);		\
62} while (/*CONSTCOND*/0)
63
64/*
65 * OpenPAM internal
66 *
67 * Substitute PAM item values in a string
68 */
69
70int
71openpam_subst(const pam_handle_t *pamh,
72    char *buf, size_t *bufsize, const char *template)
73{
74	size_t len;
75	int ret;
76
77	ENTERS(template);
78	if (template == NULL)
79		template = "(null)";
80
81	len = 1; /* initialize to 1 for terminating NUL */
82	ret = PAM_SUCCESS;
83	while (*template && ret == PAM_SUCCESS) {
84		if (template[0] == '%') {
85			++template;
86			switch (*template) {
87			case 's':
88				subst_item(PAM_SERVICE);
89				break;
90			case 't':
91				subst_item(PAM_TTY);
92				break;
93			case 'h':
94				subst_item(PAM_HOST);
95				break;
96			case 'u':
97				subst_item(PAM_USER);
98				break;
99			case 'H':
100				subst_item(PAM_RHOST);
101				break;
102			case 'U':
103				subst_item(PAM_RUSER);
104				break;
105			case '\0':
106				subst_char('%');
107				break;
108			default:
109				subst_char('%');
110				subst_char(*template);
111			}
112			if (*template)
113				++template;
114		} else {
115			subst_char(*template++);
116		}
117	}
118	if (buf)
119		*buf = '\0';
120	if (ret == PAM_SUCCESS) {
121		if (len > *bufsize)
122			ret = PAM_TRY_AGAIN;
123		*bufsize = len;
124	}
125	RETURNC(ret);
126}
127
128/*
129 * Error codes:
130 *
131 *	=pam_get_item
132 *	!PAM_SYMBOL_ERR
133 *	PAM_TRY_AGAIN
134 */
135
136/**
137 * The =openpam_subst function expands a string, substituting PAM item
138 * values for all occurrences of specific substitution codes.
139 * The =template argument points to the initial string.
140 * The result is stored in the buffer pointed to by the =buf argument; the
141 * =bufsize argument specifies the size of that buffer.
142 * The actual size of the resulting string, including the terminating NUL
143 * character, is stored in the location pointed to by the =bufsize
144 * argument.
145 *
146 * If =buf is NULL, or if the buffer is too small to hold the expanded
147 * string, =bufsize is updated to reflect the amount of space required to
148 * hold the entire string, and =openpam_subst returns =PAM_TRY_AGAIN.
149 *
150 * If =openpam_subst fails for any other reason, the =bufsize argument is
151 * untouched, but part of the buffer may still have been overwritten.
152 *
153 * Substitution codes are introduced by a percent character and correspond
154 * to PAM items:
155 *
156 *	%H:
157 *		Replaced by the current value of the =PAM_RHOST item.
158 *	%h:
159 *		Replaced by the current value of the =PAM_HOST item.
160 *	%s:
161 *		Replaced by the current value of the =PAM_SERVICE item.
162 *	%t:
163 *		Replaced by the current value of the =PAM_TTY item.
164 *	%U:
165 *		Replaced by the current value of the =PAM_RUSER item.
166 *	%u:
167 *		Replaced by the current value of the =PAM_USER item.
168 *
169 * >pam_get_authtok
170 * >pam_get_item
171 * >pam_get_user
172 *
173 * AUTHOR DES
174 */
175