1121054Semax/*-
2121054Semax * Copyright (c) 2011-2023 Dag-Erling Sm��rgrav
3121054Semax * All rights reserved.
4121054Semax *
5121054Semax * Redistribution and use in source and binary forms, with or without
6121054Semax * modification, are permitted provided that the following conditions
7121054Semax * are met:
8121054Semax * 1. Redistributions of source code must retain the above copyright
9121054Semax *    notice, this list of conditions and the following disclaimer.
10121054Semax * 2. Redistributions in binary form must reproduce the above copyright
11121054Semax *    notice, this list of conditions and the following disclaimer in the
12121054Semax *    documentation and/or other materials provided with the distribution.
13121054Semax * 3. The name of the author may not be used to endorse or promote
14121054Semax *    products derived from this software without specific prior written
15121054Semax *    permission.
16121054Semax *
17121054Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18121054Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19121054Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20121054Semax * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21121054Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22121054Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23121054Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24121054Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25121054Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26121054Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27121054Semax * SUCH DAMAGE.
28121054Semax */
29121054Semax
30121054Semax#ifdef HAVE_CONFIG_H
31121054Semax# include "config.h"
32121054Semax#endif
33121054Semax
34121054Semax#include <security/pam_appl.h>
35121054Semax
36121054Semax#include "openpam_impl.h"
37121054Semax
38121054Semax#define subst_char(ch) do {			\
39121054Semax	int ch_ = (ch);				\
40121054Semax	if (buf && len < *bufsize)		\
41121054Semax		*buf++ = ch_;			\
42121054Semax	++len;					\
43121054Semax} while (0)
44124317Semax
45124317Semax#define subst_string(s) do {			\
46121054Semax	const char *s_ = (s);			\
47121054Semax	while (*s_)				\
48121054Semax		subst_char(*s_++);		\
49121054Semax} while (0)
50121054Semax
51121054Semax#define subst_item(i) do {			\
52121054Semax	int i_ = (i);				\
53121054Semax	const void *p_;				\
54121054Semax	ret = pam_get_item(pamh, i_, &p_);	\
55124317Semax	if (ret == PAM_SUCCESS && p_ != NULL)	\
56124317Semax		subst_string(p_);		\
57124317Semax} while (0)
58121054Semax
59121054Semax/*
60124758Semax * OpenPAM internal
61121054Semax *
62121054Semax * Substitute PAM item values in a string
63124317Semax */
64121054Semax
65124317Semaxint
66121054Semaxopenpam_subst(const pam_handle_t *pamh,
67121054Semax    char *buf, size_t *bufsize, const char *template)
68121054Semax{
69121054Semax	size_t len;
70121054Semax	int ret;
71121054Semax
72121054Semax	ENTERS(template);
73121054Semax	if (template == NULL)
74121054Semax		template = "(null)";
75121054Semax
76124317Semax	len = 1; /* initialize to 1 for terminating NUL */
77124317Semax	ret = PAM_SUCCESS;
78124317Semax	while (*template && ret == PAM_SUCCESS) {
79124317Semax		if (template[0] == '%') {
80124317Semax			++template;
81124317Semax			switch (*template) {
82124317Semax			case 's':
83124317Semax				subst_item(PAM_SERVICE);
84121054Semax				break;
85121054Semax			case 't':
86121054Semax				subst_item(PAM_TTY);
87121054Semax				break;
88121054Semax			case 'h':
89121054Semax				subst_item(PAM_HOST);
90121054Semax				break;
91121054Semax			case 'u':
92121054Semax				subst_item(PAM_USER);
93121054Semax				break;
94121054Semax			case 'H':
95121054Semax				subst_item(PAM_RHOST);
96121054Semax				break;
97124317Semax			case 'U':
98121054Semax				subst_item(PAM_RUSER);
99121054Semax				break;
100121054Semax			case '\0':
101121054Semax				subst_char('%');
102124317Semax				break;
103124317Semax			default:
104121054Semax				subst_char('%');
105121054Semax				subst_char(*template);
106121054Semax			}
107121054Semax			if (*template)
108121054Semax				++template;
109121054Semax		} else {
110121054Semax			subst_char(*template++);
111121054Semax		}
112121054Semax	}
113121054Semax	if (buf)
114121054Semax		*buf = '\0';
115121054Semax	if (ret == PAM_SUCCESS) {
116121054Semax		if (len > *bufsize)
117121054Semax			ret = PAM_TRY_AGAIN;
118121054Semax		*bufsize = len;
119121054Semax	}
120121054Semax	RETURNC(ret);
121121054Semax}
122121054Semax
123121054Semax/*
124121054Semax * Error codes:
125121054Semax *
126121054Semax *	=pam_get_item
127121054Semax *	!PAM_SYMBOL_ERR
128121054Semax *	PAM_TRY_AGAIN
129121054Semax */
130121054Semax
131121054Semax/**
132121054Semax * The =openpam_subst function expands a string, substituting PAM item
133121054Semax * values for all occurrences of specific substitution codes.
134121054Semax * The =template argument points to the initial string.
135124317Semax * The result is stored in the buffer pointed to by the =buf argument; the
136124317Semax * =bufsize argument specifies the size of that buffer.
137124317Semax * The actual size of the resulting string, including the terminating NUL
138121054Semax * character, is stored in the location pointed to by the =bufsize
139124317Semax * argument.
140124317Semax *
141124317Semax * If =buf is NULL, or if the buffer is too small to hold the expanded
142124317Semax * string, =bufsize is updated to reflect the amount of space required to
143124317Semax * hold the entire string, and =openpam_subst returns =PAM_TRY_AGAIN.
144121054Semax *
145121054Semax * If =openpam_subst fails for any other reason, the =bufsize argument is
146121054Semax * untouched, but part of the buffer may still have been overwritten.
147121054Semax *
148121054Semax * Substitution codes are introduced by a percent character and correspond
149121054Semax * to PAM items:
150121054Semax *
151121054Semax *	%H:
152121054Semax *		Replaced by the current value of the =PAM_RHOST item.
153121054Semax *	%h:
154121054Semax *		Replaced by the current value of the =PAM_HOST item.
155121054Semax *	%s:
156121054Semax *		Replaced by the current value of the =PAM_SERVICE item.
157121054Semax *	%t:
158121054Semax *		Replaced by the current value of the =PAM_TTY item.
159121054Semax *	%U:
160121054Semax *		Replaced by the current value of the =PAM_RUSER item.
161121054Semax *	%u:
162121054Semax *		Replaced by the current value of the =PAM_USER item.
163121054Semax *
164121054Semax * >pam_get_authtok
165121054Semax * >pam_get_item
166121054Semax * >pam_get_user
167121054Semax *
168121054Semax * AUTHOR DES
169121054Semax */
170121054Semax