1 /*
2  * libmavis_userdb.c
3  * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
4  * All rights reserved.
5  *
6  * $Id: libmavis_userdb.c,v 1.13 2015/03/14 06:11:28 marc Exp $
7  *
8  */
9 
10 #define __MAVIS_userdb__
11 
12 #include "misc/sysconf.h"
13 #include "misc/strops.h"
14 #include "misc/memops.h"
15 #include "misc/io.h"
16 #include "debug.h"
17 #include "misc/rb.h"
18 #include "misc/md5crypt.h"
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <grp.h>
22 #include <dlfcn.h>
23 
24 static const char rcsid[] __attribute__ ((used)) = "$Id: libmavis_userdb.c,v 1.13 2015/03/14 06:11:28 marc Exp $";
25 
26 #define MAVIS_CTX_PRIVATE	\
27 	rb_tree_t *usertable;
28 
29 #include "mavis.h"
30 
31 struct user {
32     char *name;
33     char *passwd;
34     enum token passwd_type;
35     av_ctx *ac;
36 };
37 
38 /*
39 user = name { ... }
40 */
41 #define HAVE_mavis_parse_in
mavis_parse_in(mavis_ctx * mcx,struct sym * sym)42 static int mavis_parse_in(mavis_ctx * mcx, struct sym *sym)
43 {
44     struct user *u;
45     char *t;
46 
47     while (1) {
48 	switch (sym->code) {
49 	case S_script:
50 	    mavis_script_parse(mcx, sym);
51 	    continue;
52 	case S_user:
53 	    sym_get(sym);
54 	    parse(sym, S_equal);
55 	    u = calloc(1, sizeof(struct user));
56 	    u->name = sym->buf;
57 	    if (RB_lookup(mcx->usertable, (void *) u)) {
58 		parse_error(sym, "user '%s' already defined.", sym->buf);
59 	    }
60 	    u->name = strdup(sym->buf);
61 	    u->ac = av_new(NULL, NULL);
62 	    sym_get(sym);
63 	    parse(sym, S_openbra);
64 	    while (sym->code != S_eof && sym->code != S_closebra) {
65 		switch (sym->code) {
66 		case S_password:
67 		    sym_get(sym);
68 		    parse(sym, S_equal);
69 		    switch (sym->code) {
70 		    case S_mavis:
71 		    case S_clear:
72 		    case S_crypt:
73 			break;
74 		    default:
75 			parse_error_expect(sym, S_clear, S_crypt, S_mavis, S_unknown);
76 		    }
77 		    u->passwd_type = sym->code;
78 		    sym_get(sym);
79 		    if (u->passwd_type != S_mavis) {
80 			strset(&u->passwd, sym->buf);
81 			sym_get(sym);
82 		    }
83 		    break;
84 		case S_userid:
85 		    sym_get(sym);
86 		    parse(sym, S_equal);
87 		    av_set(u->ac, AV_A_UID, sym->buf);
88 		    sym_get(sym);
89 		    break;
90 		case S_groupid:
91 		    sym_get(sym);
92 		    parse(sym, S_equal);
93 		    av_set(u->ac, AV_A_GIDS, sym->buf);
94 		    t = strchr(sym->buf, ',');
95 		    if (t)
96 			*t = 0;
97 		    av_set(u->ac, AV_A_GID, sym->buf);
98 		    sym_get(sym);
99 		    break;
100 		case S_cert:
101 		    sym_get(sym);
102 		    parse(sym, S_subject);
103 		    parse(sym, S_equal);
104 		    av_set(u->ac, AV_A_CERTSUBJ, sym->buf);
105 		    sym_get(sym);
106 		    break;
107 		case S_root:
108 		    sym_get(sym);
109 		    parse(sym, S_equal);
110 		    av_set(u->ac, AV_A_ROOT, sym->buf);
111 		    sym_get(sym);
112 		    break;
113 		case S_home:
114 		    sym_get(sym);
115 		    parse(sym, S_equal);
116 		    av_set(u->ac, AV_A_HOME, sym->buf);
117 		    sym_get(sym);
118 		    break;
119 		case S_set:
120 		    {
121 			int attr;
122 			sym_get(sym);
123 			attr = av_attribute_to_i(sym->buf);
124 			if (attr < 0)
125 			    parse_error(sym, "Unknown attribute '%s'", sym->buf);
126 			sym_get(sym);
127 			parse(sym, S_equal);
128 			av_set(u->ac, attr, sym->buf);
129 			sym_get(sym);
130 			break;
131 		    }
132 		default:
133 		    parse_error_expect(sym, S_script, S_password, S_userid, S_groupid, S_cert, S_root, S_home, S_unknown);
134 		}
135 	    }
136 	    parse(sym, S_closebra);
137 	    RB_insert(mcx->usertable, u);
138 	    continue;
139 	case S_eof:
140 	case S_closebra:
141 	    return MAVIS_CONF_OK;
142 	default:
143 	    parse_error_expect(sym, S_user, S_closebra, S_unknown);
144 	}
145     }
146 }
147 
148 #define HAVE_mavis_drop_in
mavis_drop_in(mavis_ctx * mcx)149 static void mavis_drop_in(mavis_ctx * mcx)
150 {
151     RB_tree_delete(mcx->usertable);
152 }
153 
154 #define HAVE_mavis_send_in
mavis_send_in(mavis_ctx * mcx,av_ctx ** ac)155 static int mavis_send_in(mavis_ctx * mcx, av_ctx ** ac)
156 {
157     char *t, *m, *p;
158     struct user *u = alloca(sizeof(struct user));
159 
160     t = av_get(*ac, AV_A_TYPE);
161 
162     if (strcmp(t, AV_V_TYPE_FTP))
163 	return MAVIS_DOWN;
164 
165     m = av_get(*ac, AV_A_FTP_ANONYMOUS);
166     if (m && !strcmp(m, AV_V_BOOL_TRUE))
167 	return MAVIS_DOWN;
168 
169     u->name = av_get(*ac, AV_A_USER);
170 
171     u = (struct user *) RB_lookup(mcx->usertable, (void *) u);
172     if (!u || u->passwd_type == S_mavis)
173 	return MAVIS_DOWN;
174 
175     p = av_get(*ac, AV_A_PASSWORD);
176 
177     if (u->passwd_type == S_clear)
178 	av_set(*ac, AV_A_DBPASSWORD, u->passwd);
179     else if (!strncmp(u->passwd, "$1$", 3)) {
180 	if (!strcmp(u->passwd, md5crypt(p, u->passwd)))
181 	    av_set(*ac, AV_A_DBPASSWORD, p);
182     } else if (!strcmp(u->passwd, crypt(p, u->passwd)))
183 	av_set(*ac, AV_A_DBPASSWORD, p);
184 
185     av_merge(*ac, u->ac);
186 
187     return MAVIS_FINAL;
188 }
189 
190 #define HAVE_mavis_recv_out
mavis_recv_out(mavis_ctx * mcx,av_ctx ** ac)191 static int mavis_recv_out(mavis_ctx * mcx, av_ctx ** ac)
192 {
193     char *t, *m;
194     struct user *u = alloca(sizeof(struct user));
195 
196     t = av_get(*ac, AV_A_TYPE);
197 
198     if (strcmp(t, AV_V_TYPE_FTP))
199 	return MAVIS_DOWN;
200 
201     m = av_get(*ac, AV_A_FTP_ANONYMOUS);
202     if (m && !strcmp(m, AV_V_BOOL_TRUE))
203 	return MAVIS_DOWN;
204 
205     u->name = av_get(*ac, AV_A_USER);
206 
207     u = (struct user *) RB_lookup(mcx->usertable, (void *) u);
208     if (!u || u->passwd_type != S_mavis)
209 	return MAVIS_DOWN;
210 
211     av_merge(*ac, u->ac);
212 
213     return MAVIS_FINAL;
214 }
215 
compare_user(const void * a,const void * b)216 static int compare_user(const void *a, const void *b)
217 {
218     return strcmp(((struct user *) a)->name, ((struct user *) b)->name);
219 }
220 
free_user(struct user * user)221 static void free_user(struct user *user)
222 {
223     Xfree(&user->name);
224     Xfree(&user->passwd);
225     av_free(user->ac);
226     free(user);
227 }
228 
229 #define HAVE_mavis_new
mavis_new(mavis_ctx * mcx)230 static void mavis_new(mavis_ctx * mcx)
231 {
232     mcx->usertable = RB_tree_new(compare_user, (void (*)(void *)) free_user);
233 }
234 
235 #define MAVIS_name "userdb"
236 #include "mavis_glue.c"
237