1 /*
2 (C) 2012, 2016 Percona LLC and/or its affiliates
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18 #include "auth_mapping.h"
19 #include "groups.h"
20 #include <string.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23
24 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
25
26 /** Token representation:
27 token type, string repr, length of token */
28 struct token
29 {
30 enum { tok_id, tok_comma, tok_eq, tok_eof } token_type;
31 const char *token;
32 size_t token_len;
33 };
34
35 /** Iterator in key-value mapping:
36 position and length of key,
37 position and length of value,
38 current position in string */
39 struct mapping_iter {
40 const char *key;
41 size_t key_len;
42 const char *value;
43 size_t value_len;
44 const char *ptr;
45 };
46
47 /** Get next token from buf. Returns new buf position. */
get_token(struct token * token,const char * buf)48 static const char *get_token(struct token *token,
49 const char *buf)
50 {
51 const char *ptr= buf;
52
53 while (*ptr && isspace(*ptr))
54 ++ptr;
55
56 token->token= ptr;
57 switch (*ptr)
58 {
59 case '\0':
60 token->token_type= tok_eof;
61 break;
62 case ',':
63 token->token_len= 1;
64 token->token_type = tok_comma;
65 ++ptr;
66 break;
67 case '=':
68 token->token_len= 1;
69 token->token_type = tok_eq;
70 ++ptr;
71 break;
72 case '"':
73 token->token_len= 0;
74 ++ptr;
75 token->token= ptr;
76 while (*ptr && *ptr != '"')
77 {
78 ++token->token_len;
79 ++ptr;
80 }
81 token->token_type= tok_id;
82 if (*ptr)
83 ++ptr;
84 break;
85 default:
86 token->token_len= 0;
87 while (*ptr && !isspace(*ptr) && *ptr != ',' && *ptr != '=')
88 {
89 ++token->token_len;
90 ++ptr;
91 }
92 token->token_type= tok_id;
93 }
94
95 return ptr;
96 }
97
98 /** Create iterator through mapping string.
99 Initially iterator set to position before first
100 key-value pair. On success non-NULL pointer returned, otherwise NULL */
mapping_iter_new(const char * mapping_string)101 struct mapping_iter *mapping_iter_new(const char *mapping_string)
102 {
103 struct mapping_iter *it= malloc(sizeof(struct mapping_iter));
104 struct token token;
105 if (it != NULL)
106 {
107 it->key= NULL;
108 it->value= NULL;
109 /* eat up service name and move to (, key = value)* part */
110 it->ptr= get_token(&token, mapping_string);
111 }
112 return it;
113 }
114
115 /** Move iterator to next key-value pair.
116 On success pointer to key position in string returned,
117 otherwise NULL */
mapping_iter_next(struct mapping_iter * it)118 const char *mapping_iter_next(struct mapping_iter *it)
119 {
120 struct token token[4]= {{0, 0, 0}};
121
122 /* read next 4 tokens */
123 it->ptr= get_token(token + 3,
124 get_token(token + 2,
125 get_token(token + 1,
126 get_token(token, it->ptr))));
127
128 /* was it ", id = id"? */
129 if (!((token[0].token_type == tok_comma) &&
130 (token[1].token_type == tok_id) &&
131 (token[2].token_type == tok_eq) &&
132 (token[3].token_type == tok_id)))
133 {
134 /* we got something inconsistent */
135 return NULL;
136 }
137
138 /* set key */
139 it->key= token[1].token;
140 it->key_len= token[1].token_len;
141
142 /* set value */
143 it->value= token[3].token;
144 it->value_len= token[3].token_len;
145
146 return it->key;
147 }
148
149 /** Finish iteration and release iterator */
mapping_iter_free(struct mapping_iter * it)150 void mapping_iter_free(struct mapping_iter *it)
151 {
152 free(it);
153 }
154
155 /** Get mapped value for given user name.
156 Value is looked up by using all user groups as a key.
157 Auth string is iterated only once, while groups are iterated
158 for every key-value pair. This is mean than auth string order
159 is dominant.
160
161 Example:
162
163 given:
164 user "foo" is the member of "wheel", "staff" and "bar".
165 auth string is "mysql, root=user1, bar=user2, staff=user3"
166
167 result is "user2".
168
169 On success value_buf returned, otherwise NULL */
mapping_lookup_user(const char * user_name,char * value_buf,size_t value_buf_len,const char * mapping_string)170 char *mapping_lookup_user(const char *user_name,
171 char *value_buf, size_t value_buf_len,
172 const char *mapping_string)
173 {
174 /* Iterate through the key-value list stored in auth_string and
175 find key (which is interpreted as group name) in the list of groups
176 for specified user. If match is found, store appropriate value in
177 the authenticated_as field. */
178 struct groups_iter *group_it;
179 struct mapping_iter *keyval_it;
180 const char *key;
181 const char *group;
182
183 keyval_it= mapping_iter_new(mapping_string);
184 if (keyval_it == NULL)
185 return NULL;
186
187 group_it= groups_iter_new(user_name);
188 if (group_it == NULL)
189 {
190 mapping_iter_free(keyval_it);
191 return NULL;
192 }
193
194 while ((key= mapping_iter_next(keyval_it)) != NULL) {
195 while ((group= groups_iter_next(group_it)) != NULL) {
196 if (keyval_it->key_len == strlen(group) &&
197 strncmp(key, group, keyval_it->key_len) == 0) {
198 /* match is found */
199 memcpy(value_buf, keyval_it->value,
200 MIN(value_buf_len, keyval_it->value_len));
201 value_buf[MIN(value_buf_len, keyval_it->value_len)]= '\0';
202 groups_iter_free(group_it);
203 mapping_iter_free(keyval_it);
204 return value_buf;
205 }
206 }
207 groups_iter_reset(group_it);
208 }
209
210 groups_iter_free(group_it);
211 mapping_iter_free(keyval_it);
212
213 return NULL;
214 }
215
216 /** Get key in current iterator pos. On success buf returned,
217 otherwise NULL */
mapping_iter_get_key(struct mapping_iter * it,char * buf,size_t buf_len)218 char *mapping_iter_get_key(struct mapping_iter *it, char *buf, size_t buf_len)
219 {
220 if (it->key == NULL)
221 return NULL;
222 memcpy(buf, it->key, MIN(buf_len, it->key_len));
223 buf[MIN(buf_len, it->key_len)]= '\0';
224 return buf;
225 }
226
227 /** Get value in current iterator pos. On success buf returned,
228 otherwise NULL */
mapping_iter_get_value(struct mapping_iter * it,char * buf,size_t buf_len)229 char *mapping_iter_get_value(struct mapping_iter *it, char *buf, size_t buf_len)
230 {
231 if (it->value == NULL)
232 return NULL;
233 memcpy(buf, it->value, MIN(buf_len, it->value_len));
234 buf[MIN(buf_len, it->value_len)]= '\0';
235 return buf;
236 }
237
238 /** Get value by key. On success pointer to service_name
239 returned, otherwise NULL */
mapping_get_service_name(char * buf,size_t buf_len,const char * mapping_string)240 char *mapping_get_service_name(char *buf, size_t buf_len,
241 const char *mapping_string)
242 {
243 struct token token;
244
245 get_token(&token, mapping_string);
246 if (token.token_type == tok_id)
247 {
248 memcpy(buf, token.token, MIN(buf_len, token.token_len));
249 buf[MIN(buf_len, token.token_len)]= '\0';
250 return buf;
251 }
252
253 return NULL;
254 }
255