1 /* Copyright 2003-2008 Wang, Chun-Pin All rights reserved. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <strings.h>
5 #include <unistd.h>
6 #include <sys/param.h>
7 #include <syslog.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <grp.h>
11 #include <pwd.h>
12 #include <ctype.h>
13
14 #include "smbftpd.h"
15 #include "auth.h"
16
17 #ifndef LINE_MAX
18 #define LINE_MAX 2048
19 #endif
20
set_get_value(struct opt_set * set,const char * user)21 const char *set_get_value(struct opt_set *set, const char *user)
22 {
23 struct opt_set *p = set;
24 char *key;
25 int match = 0;
26
27 if (!user || !set) {
28 return NULL;
29 }
30
31 while (p) {
32 key = p->key;
33 if (*key != '@') { //user
34 if (0 == strcmp(key, user)) {
35 match = 1;
36 }
37 } else if (*(key+1) == '\0') { /* "@" match all */
38 match = 1;
39 } else { /* Group */
40 if (is_user_in_group(user, key + 1)) {
41 match = 1;
42 }
43 }
44 if (match) {
45 return p->value;
46 }
47 p = p->next;
48 }
49 return NULL;
50 }
51 /**
52 * Allocate another string and copy string "s" into new buffer.
53 * When there is double quote in s, put add another double.
54 *
55 * For example,
56 * This is "s"
57 * will become
58 * This is ""s""
59 *
60 * @param s
61 *
62 * @return Success: Returen a new string, call should free the string
63 * Malloc failed: Return NULL
64 */
doublequote(const char * s)65 char *doublequote(const char *s)
66 {
67 int n;
68 const char *p1;
69 char *p, *s2;
70
71 for (p1 = s, n = 0; *p1; p1++)
72 if (*p1 == '"')
73 n++;
74
75 if ((s2 = malloc(p1 - s + n + 1)) == NULL)
76 return(NULL);
77
78 for (p = s2; *s; s++, p++) {
79 if ((*p = *s) == '"')
80 *(++p) = '"';
81 }
82 *p = '\0';
83
84 return(s2);
85 }
86
87 /**
88 * This function will remove the spaces ' ' and tab '\t' and
89 * newline characters '\r', '\n' in the front and tail of the
90 * given "str". So the "str" buffer will be modified.
91 *
92 * if remove_quote is 1, we will also remove the in pairs double
93 * quote '"' or single quote '\''.
94 *
95 * For example, if the string is " this is a string ", it
96 * will become "this is a string".
97 *
98 * If the string is " \"this is a string\" ", when remove_quote
99 * is 1, it will become "this is a string".
100 *
101 * @param str
102 * @param remove_quote
103 *
104 * @return The pointer of str
105 */
str_trim(char * str,int remove_quote)106 static char *str_trim(char *str, int remove_quote)
107 {
108 char *head, *tail;
109
110 if (!str) {
111 return NULL;
112 }
113
114 for (head = str; isspace(*head) && *head != 0; head++);
115 for (tail = head + strlen(head) - 1; tail>head && isspace(*tail); tail--);
116
117 *(tail+1) = 0;
118
119 if (remove_quote) {
120 if ((tail > head) && ((*head == '"' && *tail == '"') ||
121 (*head == '\'' && *tail == '\''))) {
122 head++;
123 *tail = 0;
124 tail--;
125 }
126 }
127
128 if (str != head) {
129 memmove(str, head, (tail - head + 2));
130 }
131
132 return str;
133 }
134
str_trim_space(char * str)135 char *str_trim_space(char *str)
136 {
137 return str_trim(str, 0);
138 }
139
str_trim_space_quote(char * str)140 char *str_trim_space_quote(char *str)
141 {
142 return str_trim(str, 1);
143 }
144
145
146 /**
147 * Check whether user is in list. The list is a string of
148 * users/groups that separate by ','. The group name has
149 * prefix @.
150 *
151 * For example szList = "user1, user2, user3, @group1, @group2..."
152 *
153 * We will get each user in the list and check when the user name
154 * is the same. When we get group, we will check whether user
155 * belongs to the group.
156 *
157 * @param user User name to check
158 * @param list The string that contains users and groups separated by ",".
159 *
160 * @return 1: Yes, the user is in the list
161 * 0: No, the user is not in the list
162 */
is_user_in_list(const char * user,const char * list)163 int is_user_in_list(const char *user, const char *list)
164 {
165 char *tmplist = NULL, *token;
166 int err = 0;
167
168 if (!user || !list) {
169 return err;
170 }
171
172 tmplist = (char *)malloc(strlen(list) + 1);
173 if (tmplist == NULL) {
174 syslog(LOG_ERR, "%s (%d) failed to allocate memory, errno:%d(%s)",
175 __FILE__, __LINE__, errno, strerror(errno));
176 return err;
177 }
178 strcpy(tmplist, list);
179
180 for (token = strtok(tmplist, ","); token; token = strtok(NULL, ",")) {
181 str_trim_space(token);
182 if (*token != '@') { //user
183 if (0 == strcmp(user, token)) {
184 err = 1;
185 break;
186 }
187 } else {
188 if (1 == smbftpd_auth_is_user_in_group(user, token+1)) {
189 err = 1;
190 goto Error;
191 }
192 }
193 }
194
195 Error:
196 if (tmplist != NULL) {
197 free(tmplist);
198 }
199 return err;
200 }
201
202 /**
203 * Check whether user belongs to group. We will check group id and
204 * its members.
205 *
206 * @param user The user name to check
207 * @param group The group name to search
208 *
209 * @return 1: Yes, the user belongs to the group.
210 * 0: No, not belongs to the group.
211 */
is_user_in_group(const char * user,const char * group)212 int is_user_in_group(const char *user, const char *group)
213 {
214 return smbftpd_auth_is_user_in_group(user, group);
215 }
216
217 /**
218 * Config file parser function. This function is used to parse config
219 * file that is the following format:
220 *
221 * Option1 Value
222 * Option2 Value
223 *
224 * We will read each line of config file and pass the option/value to
225 * the opt_handler function.
226 *
227 * The opt_handler function will then assign/convert the value to
228 * proper format.
229 *
230 * @param file The path of the config file.
231 * @param opt_handler
232 * The option/value handler function.
233 *
234 * @return 0: Success
235 * -1: Failed
236 */
smbftpd_config_parser(const char * file,int (* opt_handler)(char * option,char * opt_arg))237 int smbftpd_config_parser(const char *file, int (*opt_handler)(char *option, char *opt_arg))
238 {
239 FILE *pf = NULL;
240 char line[LINE_MAX];
241 char *option, *opt_arg;
242 int error = -1, len = 0;
243
244 if (NULL == file || !opt_handler) {
245 return -1;
246 }
247
248 pf = fopen(file, "r");
249 if (!pf) {
250 syslog(LOG_ERR, "%s (%d) Failed to open [%s] (%s)", __FILE__, __LINE__,
251 file, strerror(errno));
252 return -1;
253 }
254
255 while (NULL != (fgets(line, sizeof(line), pf))) {
256 len = strlen(line);
257
258 if (line[len - 1] == '\n') {
259 line[len - 1] = '\0';
260 }
261 option = line;
262 // Trim space
263 while ((*option == ' ') || (*option == '\t')) {
264 option++;
265 }
266 if (*option == '\0' || *option == '#') {
267 continue;
268 }
269
270 opt_arg = option;
271 while ((*opt_arg != ' ') && (*opt_arg != '\t') && (*opt_arg != '\0')) {
272 opt_arg++;
273 }
274 if (opt_arg == option) {
275 // Empty line
276 continue;
277 }
278
279 *opt_arg = '\0';
280 opt_arg++;
281 str_trim_space_quote(opt_arg);
282 if (*opt_arg == '\0') {
283 syslog(LOG_ERR, "%s (%d) bad syntax of config option %s",
284 __FILE__, __LINE__, option);
285 goto Error;
286 }
287
288 if (0 != opt_handler(option, opt_arg)) {
289 goto Error;
290 }
291 }
292
293 error = 0;
294 Error:
295 if (pf) {
296 fclose(pf);
297 }
298
299 return error;
300 }
301