1228690Sdes/*-
2228690Sdes * Copyright (c) 2011 Dag-Erling Sm��rgrav
3228690Sdes * All rights reserved.
4228690Sdes *
5228690Sdes * Redistribution and use in source and binary forms, with or without
6228690Sdes * modification, are permitted provided that the following conditions
7228690Sdes * are met:
8228690Sdes * 1. Redistributions of source code must retain the above copyright
9255376Sdes *    notice, this list of conditions and the following disclaimer.
10228690Sdes * 2. Redistributions in binary form must reproduce the above copyright
11228690Sdes *    notice, this list of conditions and the following disclaimer in the
12228690Sdes *    documentation and/or other materials provided with the distribution.
13236099Sdes * 3. The name of the author may not be used to endorse or promote
14236099Sdes *    products derived from this software without specific prior written
15236099Sdes *    permission.
16228690Sdes *
17228690Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18228690Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19228690Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20228690Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21228690Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22228690Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23228690Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24228690Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25228690Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26228690Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27228690Sdes * SUCH DAMAGE.
28228690Sdes *
29255376Sdes * $Id: openpam_subst.c 648 2013-03-05 17:54:27Z des $
30228690Sdes */
31228690Sdes
32228690Sdes#ifdef HAVE_CONFIG_H
33228690Sdes# include "config.h"
34228690Sdes#endif
35228690Sdes
36228690Sdes#include <security/pam_appl.h>
37228690Sdes
38228690Sdes#include "openpam_impl.h"
39228690Sdes
40228690Sdes#define subst_char(ch) do {			\
41228690Sdes	int ch_ = (ch);				\
42228690Sdes	if (buf && len < *bufsize)		\
43228690Sdes		*buf++ = ch_;			\
44228690Sdes	++len;					\
45228690Sdes} while (0)
46228690Sdes
47228690Sdes#define subst_string(s) do {			\
48228690Sdes	const char *s_ = (s);			\
49228690Sdes	while (*s_)				\
50228690Sdes		subst_char(*s_++);		\
51228690Sdes} while (0)
52228690Sdes
53228690Sdes#define subst_item(i) do {			\
54228690Sdes	int i_ = (i);				\
55228690Sdes	const void *p_;				\
56228690Sdes	ret = pam_get_item(pamh, i_, &p_);	\
57228690Sdes	if (ret == PAM_SUCCESS && p_ != NULL)	\
58228690Sdes		subst_string(p_);		\
59228690Sdes} while (0)
60228690Sdes
61228690Sdes/*
62228690Sdes * OpenPAM internal
63228690Sdes *
64228690Sdes * Substitute PAM item values in a string
65228690Sdes */
66228690Sdes
67228690Sdesint
68228690Sdesopenpam_subst(const pam_handle_t *pamh,
69228690Sdes    char *buf, size_t *bufsize, const char *template)
70228690Sdes{
71228690Sdes	size_t len;
72228690Sdes	int ret;
73228690Sdes
74228690Sdes	ENTERS(template);
75228690Sdes	if (template == NULL)
76228690Sdes		template = "(null)";
77228690Sdes
78228690Sdes	len = 1; /* initialize to 1 for terminating NUL */
79228690Sdes	ret = PAM_SUCCESS;
80228690Sdes	while (*template && ret == PAM_SUCCESS) {
81228690Sdes		if (template[0] == '%') {
82228690Sdes			++template;
83228690Sdes			switch (*template) {
84228690Sdes			case 's':
85228690Sdes				subst_item(PAM_SERVICE);
86228690Sdes				break;
87228690Sdes			case 't':
88228690Sdes				subst_item(PAM_TTY);
89228690Sdes				break;
90228690Sdes			case 'h':
91228690Sdes				subst_item(PAM_HOST);
92228690Sdes				break;
93228690Sdes			case 'u':
94228690Sdes				subst_item(PAM_USER);
95228690Sdes				break;
96228690Sdes			case 'H':
97228690Sdes				subst_item(PAM_RHOST);
98228690Sdes				break;
99228690Sdes			case 'U':
100228690Sdes				subst_item(PAM_RUSER);
101228690Sdes				break;
102228690Sdes			case '\0':
103228690Sdes				subst_char('%');
104228690Sdes				break;
105228690Sdes			default:
106228690Sdes				subst_char('%');
107228690Sdes				subst_char(*template);
108228690Sdes			}
109228690Sdes			++template;
110228690Sdes		} else {
111228690Sdes			subst_char(*template++);
112228690Sdes		}
113228690Sdes	}
114228690Sdes	if (buf)
115228690Sdes		*buf = '\0';
116228690Sdes	if (ret == PAM_SUCCESS) {
117228690Sdes		if (len > *bufsize)
118228690Sdes			ret = PAM_TRY_AGAIN;
119228690Sdes		*bufsize = len;
120228690Sdes	}
121228690Sdes	RETURNC(ret);
122228690Sdes}
123228690Sdes
124228690Sdes/*
125228690Sdes * Error codes:
126228690Sdes *
127228690Sdes *	=pam_get_item
128228690Sdes *	!PAM_SYMBOL_ERR
129228690Sdes *	PAM_TRY_AGAIN
130228690Sdes */
131228690Sdes
132228690Sdes/**
133228690Sdes * The =openpam_subst function expands a string, substituting PAM item
134228690Sdes * values for all occurrences of specific substitution codes.
135228690Sdes * The =template argument points to the initial string.
136228690Sdes * The result is stored in the buffer pointed to by the =buf argument; the
137228690Sdes * =bufsize argument specifies the size of that buffer.
138228690Sdes * The actual size of the resulting string, including the terminating NUL
139228690Sdes * character, is stored in the location pointed to by the =bufsize
140228690Sdes * argument.
141228690Sdes *
142228690Sdes * If =buf is NULL, or if the buffer is too small to hold the expanded
143228690Sdes * string, =bufsize is updated to reflect the amount of space required to
144228690Sdes * hold the entire string, and =openpam_subst returns =PAM_TRY_AGAIN.
145228690Sdes *
146228690Sdes * If =openpam_subst fails for any other reason, the =bufsize argument is
147228690Sdes * untouched, but part of the buffer may still have been overwritten.
148228690Sdes *
149228690Sdes * Substitution codes are introduced by a percent character and correspond
150228690Sdes * to PAM items:
151228690Sdes *
152228690Sdes *	%H:
153228690Sdes *		Replaced by the current value of the =PAM_RHOST item.
154228690Sdes *	%h:
155228690Sdes *		Replaced by the current value of the =PAM_HOST item.
156228690Sdes *	%s:
157228690Sdes *		Replaced by the current value of the =PAM_SERVICE item.
158228690Sdes *	%t:
159228690Sdes *		Replaced by the current value of the =PAM_TTY item.
160228690Sdes *	%U:
161228690Sdes *		Replaced by the current value of the =PAM_RUSER item.
162228690Sdes *	%u:
163228690Sdes *		Replaced by the current value of the =PAM_USER item.
164228690Sdes *
165228690Sdes * >pam_get_authtok
166228690Sdes * >pam_get_item
167228690Sdes * >pam_get_user
168228690Sdes *
169228690Sdes * AUTHOR DES
170228690Sdes */
171