1 /* This file is part of pam-modules.
2 Copyright (C) 2009-2012, 2014-2015, 2018 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <graypam.h>
18
19 struct keyword *
gray_find_keyword(struct keyword * kwtab,const char * str,size_t len)20 gray_find_keyword(struct keyword *kwtab, const char *str, size_t len)
21 {
22 for (; kwtab->name; kwtab++)
23 if (kwtab->len == len
24 && strncmp(kwtab->name, str, kwtab->len) == 0)
25 return kwtab;
26 return NULL;
27 }
28
29 static struct keyword vartab[] = {
30 DCL("service", PAM_SERVICE),
31 DCL("user", PAM_USER),
32 DCL("tty", PAM_TTY),
33 DCL("rhost", PAM_RHOST),
34 DCL("ruser", PAM_RUSER),
35 DCL("prompt", PAM_USER_PROMPT),
36 DCL("password", PAM_AUTHTOK),
37 { NULL }
38 };
39
40 static int
var_tok(const char * str,const char ** pvar,size_t * plen)41 var_tok(const char *str, const char ** pvar, size_t *plen)
42 {
43 size_t len;
44
45 for (len = 0; str[len]; len++) {
46 if (str[len] == '}' || str[len] == ':') {
47 *pvar = str;
48 *plen = len;
49 return 0;
50 }
51 }
52 return 1;
53 }
54
55 static int
repl_tok(const char * str,const char ** pret,size_t * plen)56 repl_tok(const char *str, const char ** pret, size_t *plen)
57 {
58 size_t len;
59
60 for (len = 0; str[len]; len++) {
61 if (str[len] == '}') {
62 *pret = str;
63 *plen = len;
64 return 0;
65 }
66 }
67 return 1;
68 }
69
70 #define ISKW(c) ((c) && (isalnum(c) || (c) == '_'))
71
72 static int
get_variable(pam_handle_t * pamh,const char * str,gray_slist_t slist,const char ** endp)73 get_variable(pam_handle_t *pamh, const char *str, gray_slist_t slist,
74 const char **endp)
75 {
76 const char *name;
77 size_t namelen;
78 const char *repl = NULL;
79 size_t repllen = 0;
80 const char *val;
81 size_t vallen;
82 struct keyword *kw;
83 const char *end;
84 int rc;
85
86 str++; /* Get past the initial $ */
87 if (*str == '{') {
88 str++;
89
90 if (var_tok(str, &name, &namelen))
91 return 1;
92
93 end = str + namelen;
94 if (*end == ':') {
95 end++;
96 if (*end == '-')
97 end++;
98 if (repl_tok(end, &repl, &repllen))
99 return 1;
100 end += repllen;
101 }
102 end++;
103 } else {
104 name = end = str;
105 for (namelen = 0; ISKW(*end); namelen++, end++)
106 ;
107 }
108
109 kw = gray_find_keyword(vartab, name, namelen);
110 if (!kw) {
111 _pam_log(LOG_ERR,
112 "unknown PAM variable: %*.*s",
113 namelen, namelen, name);
114 return 1;
115 }
116
117 rc = pam_get_item(pamh, kw->code, (const void**) &val);
118 if (rc) {
119 _pam_log(LOG_ERR,
120 "cannot obtain variable %s: %s",
121 kw->name, pam_strerror(pamh, rc));
122 return 1;
123 }
124
125 if (!val) {
126 if (repl) {
127 val = repl;
128 vallen = repllen;
129 } else {
130 val = "";
131 vallen = 0;
132 }
133 } else
134 vallen = strlen(val);
135
136 gray_escape_string(slist, val, vallen);
137 *endp = end;
138 return 0;
139 }
140
141 void
gray_expand_argv(pam_handle_t * pamh,int argc,const char ** argv,gray_slist_t slist)142 gray_expand_argv(pam_handle_t *pamh, int argc, const char **argv,
143 gray_slist_t slist)
144 {
145 int i;
146
147 for (i = 0; i < argc; i++) {
148 if (i > 0)
149 gray_slist_append_char(slist, ' ');
150 if (strchr(argv[i], '$') == 0)
151 gray_slist_append(slist, argv[i], strlen(argv[i]));
152 else {
153 const char *p;
154
155 for (p = argv[i]; *p; p++) {
156 if (*p == '\\') {
157 p++;
158 gray_slist_append_char(slist, *p);
159 } else if (*p == '$') {
160 if (get_variable(pamh, p, slist, &p))
161 gray_slist_append_char(slist,
162 *p);
163 else
164 p--;
165 } else
166 gray_slist_append_char(slist, *p);
167 }
168 }
169 }
170 }
171
172 void
gray_expand_string(pam_handle_t * pamh,const char * str,gray_slist_t slist)173 gray_expand_string(pam_handle_t *pamh, const char *str, gray_slist_t slist)
174 {
175 const char *p;
176 #define FLUSH() gray_slist_append(slist, str, p - str); str = p
177
178 for (p = str; *p; ) {
179 if (*p == '\\') {
180 FLUSH();
181 p++;
182 if (*p) {
183 gray_slist_append_char(slist, *p);
184 p++;
185 } else {
186 gray_slist_append_char(slist, '\\');
187 break;
188 }
189 str = p;
190 } else if (*p == '$') {
191 FLUSH();
192 if (get_variable(pamh, p, slist, &p)) {
193 gray_slist_append_char(slist, *p);
194 p++;
195 }
196 str = p;
197 } else
198 p++;
199 }
200 FLUSH();
201 }
202