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
70 int
openpam_subst(const pam_handle_t * pamh,char * buf,size_t * bufsize,const char * template)71 openpam_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