Imported Upstream version 0.66.1
[hcoop/debian/courier-authlib.git] / authsqlitelib.c
1 /*
2 ** Copyright 2012 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <ctype.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <time.h>
14
15 #include "authsqlite.h"
16 #include "authsqliterc.h"
17 #include "auth.h"
18 #include "courierauthdebug.h"
19
20 #define err courier_auth_err
21 #define GET(c) ((c) < (n) && columns[(c)] ? columns[(c)]:"")
22
23 static const char *read_env(const char *env)
24 {
25 return authgetconfig(AUTHSQLITERC, env);
26 }
27
28 static sqlite3 *dbh=0;
29
30 sqlite3 *do_connect()
31 {
32 const char *p;
33
34 if (dbh)
35 return dbh;
36
37 p=read_env("SQLITE_DATABASE");
38
39 if (!p)
40 return 0;
41
42 if (access(p, R_OK))
43 return 0;
44
45 if (sqlite3_open_v2(p, &dbh, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK)
46 {
47 if (dbh)
48 {
49 err("sqllite3_open(%s): %s", p, sqlite3_errmsg(dbh));
50 sqlite3_close(dbh);
51 dbh=0;
52 }
53 return 0;
54 }
55
56 return dbh;
57 }
58
59 void auth_sqlite_cleanup()
60 {
61 if (dbh)
62 {
63 sqlite3_close(dbh);
64 dbh=0;
65 }
66 }
67
68 static char *escape_str(const char *c, size_t n)
69 {
70 char *p=malloc(n+1), *q;
71
72 if (!p)
73 {
74 perror("malloc");
75 return 0;
76 }
77
78 memcpy(p, c, n);
79 p[n]=0;
80
81 q=sqlite3_mprintf("%q", p);
82 free(p);
83
84 p=strdup(q);
85 sqlite3_free(q);
86 if (!p)
87 {
88 perror("malloc");
89 return 0;
90 }
91 return p;
92 }
93
94 static struct authsqliteuserinfo ui={0, 0, 0, 0, 0, 0, 0, 0};
95 static int ui_cnt;
96
97 static void initui()
98 {
99
100 if (ui.username)
101 free(ui.username);
102 if (ui.cryptpw)
103 free(ui.cryptpw);
104 if (ui.clearpw)
105 free(ui.clearpw);
106 if (ui.home)
107 free(ui.home);
108 if (ui.maildir)
109 free(ui.maildir);
110 if (ui.quota)
111 free(ui.quota);
112 if (ui.fullname)
113 free(ui.fullname);
114 if (ui.options)
115 free(ui.options);
116 memset(&ui, 0, sizeof(ui));
117 }
118
119 static int select_callback(void *dummy, int n, char **columns, char **names)
120 {
121 if (ui_cnt++)
122 {
123 err("Multiple rows returned");
124 return -1;
125 }
126
127 initui();
128
129 if (n < 6)
130 {
131 err("Query came back with fewer than 6 columns");
132 return -1;
133 }
134
135 if ((ui.username=strdup(GET(0))) == NULL
136 || (ui.cryptpw=strdup(GET(1))) == NULL
137 || (ui.clearpw=strdup(GET(2))) == NULL
138 || (ui.home=strdup(GET(5))) == NULL
139 || (ui.maildir=strdup(GET(6))) == NULL
140 || (ui.quota=strdup(GET(7))) == NULL
141 || (ui.fullname=strdup(GET(8))) == NULL
142 || (ui.options=strdup(GET(9))) == NULL)
143 {
144 initui();
145 return 0;
146 }
147
148 ui.uid=atoi(GET(3));
149 ui.gid=atoi(GET(4));
150
151 return 0;
152 }
153
154 struct authsqliteuserinfo *auth_sqlite_getuserinfo(const char *username,
155 const char *service)
156 {
157 const char *defdomain =NULL;
158 char *querybuf;
159 char *errmsg;
160 const char *select_clause;
161
162 #define DEFAULT_SELECT_QUERY "SELECT %s, %s, %s, %s, %s, %s, %s, %s, %s, %s FROM %s WHERE %s = '%s%s%s' %s%s%s", \
163 login_field, crypt_field, clear_field, uid_field,\
164 gid_field, home_field, maildir_field, quota_field,\
165 name_field, options_field, user_table, login_field,\
166 username_escaped,\
167 has_domain || !*defdomain ? "":"@", has_domain ? "":defdomain, \
168 *where_clause ? " AND (":"", where_clause,\
169 *where_clause ? ")":""
170
171 initui();
172
173 if (!do_connect())
174 return &ui;
175
176 select_clause=read_env("SQLITE_SELECT_CLAUSE");
177 defdomain=read_env("DEFAULT_DOMAIN");
178 if (!defdomain) defdomain="";
179
180 if (!select_clause) /* siefca@pld.org.pl */
181 {
182 const char *user_table,
183 *crypt_field,
184 *clear_field,
185 *name_field,
186 *uid_field,
187 *gid_field,
188 *login_field,
189 *home_field,
190 *maildir_field,
191 *quota_field,
192 *options_field,
193 *where_clause;
194 char *username_escaped;
195 size_t query_size;
196 char dummy_buf[1];
197 int has_domain;
198
199 user_table=read_env("SQLITE_USER_TABLE");
200
201 if (!user_table)
202 {
203 err("authsqlite: SQLITE_USER_TABLE not set in "
204 AUTHSQLITERC ".");
205 return (0);
206 }
207
208 crypt_field=read_env("SQLITE_CRYPT_PWFIELD");
209 clear_field=read_env("SQLITE_CLEAR_PWFIELD");
210 name_field=read_env("SQLITE_NAME_FIELD");
211
212 if (!crypt_field && !clear_field)
213 {
214 err("authsqlite: SQLITE_CRYPT_PWFIELD and "
215 "SQLITE_CLEAR_PWFIELD not set in " AUTHSQLITERC ".");
216 return (0);
217 }
218 if (!crypt_field) crypt_field="\"\"";
219 if (!clear_field) clear_field="\"\"";
220 if (!name_field) name_field="\"\"";
221
222 uid_field = read_env("SQLITE_UID_FIELD");
223 if (!uid_field) uid_field = "uid";
224
225 gid_field = read_env("SQLITE_GID_FIELD");
226 if (!gid_field) gid_field = "gid";
227
228 login_field = read_env("SQLITE_LOGIN_FIELD");
229 if (!login_field) login_field = "id";
230
231 home_field = read_env("SQLITE_HOME_FIELD");
232 if (!home_field) home_field = "home";
233
234 maildir_field=read_env(service && strcmp(service, "courier")==0
235 ? "SQLITE_DEFAULTDELIVERY"
236 : "SQLITE_MAILDIR_FIELD");
237 if (!maildir_field) maildir_field="\"\"";
238
239 quota_field=read_env("SQLITE_QUOTA_FIELD");
240 if (!quota_field) quota_field="\"\"";
241
242 options_field=read_env("SQLITE_AUXOPTIONS_FIELD");
243 if (!options_field) options_field="\"\"";
244
245 where_clause=read_env("SQLITE_WHERE_CLAUSE");
246 if (!where_clause) where_clause = "";
247
248 username_escaped=escape_str(username, strlen(username));
249
250 if (!username_escaped)
251 {
252 perror("malloc");
253 return (0);
254 }
255
256 has_domain=strchr(username, '@') != NULL;
257
258 query_size=snprintf(dummy_buf, 1, DEFAULT_SELECT_QUERY);
259
260 querybuf=malloc(query_size+1);
261
262 if (!querybuf)
263 {
264 free(username_escaped);
265 perror("malloc");
266 return(0);
267 }
268
269 snprintf(querybuf, query_size+1, DEFAULT_SELECT_QUERY);
270 free(username_escaped);
271
272 }
273 else
274 {
275 /* siefca@pld.org.pl */
276 querybuf=auth_parse_select_clause (escape_str,
277 select_clause, username,
278 defdomain, service);
279 if (!querybuf)
280 {
281 DPRINTF("parse_select_clause failed (DEFAULT_DOMAIN not set?)");
282 return 0;
283 }
284 }
285
286 DPRINTF("SQL query: %s", querybuf);
287 errmsg=0;
288 ui_cnt=0;
289 if (sqlite3_exec(dbh, querybuf, select_callback,
290 NULL, &errmsg) != SQLITE_OK)
291 {
292 if (errmsg)
293 {
294 err(errmsg);
295 sqlite3_free(errmsg);
296 }
297
298 free(querybuf);
299 return 0;
300 }
301
302 free(querybuf);
303 if (errmsg)
304 {
305 err(errmsg);
306 sqlite3_free(errmsg);
307 }
308
309 return &ui;
310 }
311
312 static int dummy_callback(void *dummy, int n, char **columns, char **names)
313 {
314 return 0;
315 }
316
317 int auth_sqlite_setpass(const char *user, const char *pass,
318 const char *oldpass)
319 {
320 char *newpass_crypt;
321 char *sql_buf;
322 int rc=0;
323 char *errmsg;
324 char *clear_escaped;
325 char *crypt_escaped;
326
327 const char *clear_field =NULL,
328 *crypt_field =NULL,
329 *defdomain =NULL,
330 *where_clause =NULL,
331 *user_table =NULL,
332 *login_field =NULL,
333 *chpass_clause =NULL; /* siefca@pld.org.pl */
334
335 if (!do_connect()) return (-1);
336
337 if (!(newpass_crypt=authcryptpasswd(pass, oldpass)))
338 return (-1);
339
340 clear_escaped=escape_str(pass, strlen(pass));
341
342 if (!clear_escaped)
343 {
344 perror("malloc");
345 free(newpass_crypt);
346 return -1;
347 }
348
349 crypt_escaped=escape_str(newpass_crypt, strlen(newpass_crypt));
350
351 if (!crypt_escaped)
352 {
353 perror("malloc");
354 free(clear_escaped);
355 free(newpass_crypt);
356 return -1;
357 }
358
359 /* siefca@pld.org.pl */
360 chpass_clause=read_env("SQLITE_CHPASS_CLAUSE");
361 defdomain=read_env("DEFAULT_DOMAIN");
362 user_table=read_env("SQLITE_USER_TABLE");
363 if (!chpass_clause)
364 {
365 int has_domain=strchr(user, '@') != NULL;
366 char *username_escaped;
367 char dummy_buf[1];
368 size_t sql_buf_size;
369
370 username_escaped=escape_str(user, strlen(user));
371
372 if (!username_escaped)
373 {
374 perror("malloc");
375 free(clear_escaped);
376 free(crypt_escaped);
377 free(newpass_crypt);
378 return -1;
379 }
380
381 login_field = read_env("SQLITE_LOGIN_FIELD");
382 if (!login_field) login_field = "id";
383 crypt_field=read_env("SQLITE_CRYPT_PWFIELD");
384 clear_field=read_env("SQLITE_CLEAR_PWFIELD");
385 where_clause=read_env("SQLITE_WHERE_CLAUSE");
386
387 if (!where_clause)
388 where_clause="";
389
390 if (!crypt_field)
391 crypt_field="";
392
393 if (!clear_field)
394 clear_field="";
395
396 if (!defdomain)
397 defdomain="";
398
399 #define DEFAULT_SETPASS_UPDATE \
400 "UPDATE %s SET %s%s%s%s %s %s%s%s%s WHERE %s='%s%s%s' %s%s%s", \
401 user_table, \
402 *clear_field ? clear_field:"", \
403 *clear_field ? "='":"", \
404 *clear_field ? clear_escaped:"", \
405 *clear_field ? "'":"", \
406 \
407 *clear_field && *crypt_field ? ",":"", \
408 \
409 *crypt_field ? crypt_field:"", \
410 *crypt_field ? "='":"", \
411 *crypt_field ? crypt_escaped:"", \
412 *crypt_field ? "'":"", \
413 login_field, \
414 username_escaped, \
415 has_domain || !*defdomain ? "":"@", \
416 has_domain ? "":defdomain, \
417 *where_clause ? " AND (":"", where_clause, \
418 *where_clause ? ")":""
419
420
421 sql_buf_size=snprintf(dummy_buf, 1, DEFAULT_SETPASS_UPDATE);
422
423 sql_buf=malloc(sql_buf_size+1);
424
425 if (sql_buf)
426 snprintf(sql_buf, sql_buf_size+1,
427 DEFAULT_SETPASS_UPDATE);
428
429 free(username_escaped);
430 }
431 else
432 {
433 sql_buf=auth_parse_chpass_clause(escape_str, chpass_clause,
434 user,
435 defdomain,
436 clear_escaped,
437 crypt_escaped);
438 }
439
440 free(clear_escaped);
441 free(crypt_escaped);
442 free(newpass_crypt);
443
444 if (courier_authdebug_login_level >= 2)
445 {
446 DPRINTF("setpass SQL: %s", sql_buf);
447 }
448
449 errmsg=NULL;
450
451 if (sqlite3_exec(dbh, sql_buf, dummy_callback,
452 NULL, &errmsg) != SQLITE_OK)
453 {
454 rc=-1;
455 }
456 else
457 {
458 if (sqlite3_changes(dbh) > 0)
459 {
460 DPRINTF("authsqllite: password updated");
461 }
462 else
463 {
464 rc=-1;
465 DPRINTF("authsqllite: password not updated");
466 }
467 }
468
469 if (errmsg)
470 {
471 err(errmsg);
472 sqlite3_free(errmsg);
473 }
474
475 free(sql_buf);
476 return (rc);
477 }
478
479 struct enumerate_user_cb {
480
481 void (*cb_func)(const char *name,
482 uid_t uid,
483 gid_t gid,
484 const char *homedir,
485 const char *maildir,
486 const char *options,
487 void *void_arg);
488 void *void_arg;
489 };
490
491 static int enumerate_callback(void *closure,
492 int n, char **columns, char **names)
493 {
494 struct enumerate_user_cb *cb=(struct enumerate_user_cb *)closure;
495
496 const char *username;
497 uid_t uid;
498 gid_t gid;
499 const char *homedir;
500 const char *maildir;
501 const char *options;
502
503 username=GET(0);
504 uid=atol(GET(1)); /* FIXME use strtol to validate */
505 gid=atol(GET(2));
506 homedir=GET(3);
507 maildir=GET(4);
508 options=GET(5);
509
510 if (maildir && !*maildir)
511 maildir=NULL;
512
513 if (options && !*options)
514 options=NULL;
515
516 (*cb->cb_func)(username, uid, gid, homedir,
517 maildir, options, cb->void_arg);
518 return 0;
519 }
520
521 void auth_sqlite_enumerate( void(*cb_func)(const char *name,
522 uid_t uid,
523 gid_t gid,
524 const char *homedir,
525 const char *maildir,
526 const char *options,
527 void *void_arg),
528 void *void_arg)
529 {
530 const char *defdomain, *select_clause;
531 char *querybuf;
532 char *errmsg;
533 struct enumerate_user_cb cb;
534
535 cb.cb_func=cb_func;
536 cb.void_arg=void_arg;
537
538 if (!do_connect()) return;
539
540 initui();
541
542 select_clause=read_env("SQLITE_ENUMERATE_CLAUSE");
543 defdomain=read_env("DEFAULT_DOMAIN");
544 if (!defdomain || !defdomain[0])
545 defdomain="*"; /* otherwise parse_select_clause fails */
546
547 if (!select_clause)
548 {
549 const char *user_table,
550 *uid_field,
551 *gid_field,
552 *login_field,
553 *home_field,
554 *maildir_field,
555 *options_field,
556 *where_clause;
557 char dummy_buf[1];
558 size_t query_len;
559
560 user_table=read_env("SQLITE_USER_TABLE");
561
562 if (!user_table)
563 {
564 err("authsqlite: SQLITE_USER_TABLE not set in "
565 AUTHSQLITERC ".");
566 return;
567 }
568
569 uid_field = read_env("SQLITE_UID_FIELD");
570 if (!uid_field) uid_field = "uid";
571
572 gid_field = read_env("SQLITE_GID_FIELD");
573 if (!gid_field) gid_field = "gid";
574
575 login_field = read_env("SQLITE_LOGIN_FIELD");
576 if (!login_field) login_field = "id";
577
578 home_field = read_env("SQLITE_HOME_FIELD");
579 if (!home_field) home_field = "home";
580
581 maildir_field=read_env("SQLITE_MAILDIR_FIELD");
582 if (!maildir_field) maildir_field="\"\"";
583
584 options_field=read_env("SQLITE_AUXOPTIONS_FIELD");
585 if (!options_field) options_field="\"\"";
586
587 where_clause=read_env("SQLITE_WHERE_CLAUSE");
588 if (!where_clause) where_clause = "";
589
590
591 #define DEFAULT_ENUMERATE_QUERY \
592 "SELECT %s, %s, %s, %s, %s, %s FROM %s %s%s",\
593 login_field, uid_field, gid_field, \
594 home_field, maildir_field, \
595 options_field, user_table, \
596 *where_clause ? " WHERE ":"", \
597 where_clause
598
599 query_len=snprintf(dummy_buf, 1, DEFAULT_ENUMERATE_QUERY);
600
601 querybuf=malloc(query_len+1);
602
603 if (!querybuf)
604 {
605 perror("malloc");
606 return;
607 }
608
609 snprintf(querybuf, query_len+1, DEFAULT_ENUMERATE_QUERY);
610 }
611 else
612 {
613 /* siefca@pld.org.pl */
614 querybuf=auth_parse_select_clause (escape_str,
615 select_clause, "*",
616 defdomain, "enumerate");
617 if (!querybuf)
618 {
619 DPRINTF("authsqlite: parse_select_clause failed");
620 return;
621 }
622 }
623 DPRINTF("authsqlite: enumerate query: %s", querybuf);
624
625 errmsg=NULL;
626
627 sqlite3_exec(dbh, querybuf, enumerate_callback, &cb, &errmsg);
628
629 if (errmsg)
630 {
631 err(errmsg);
632 sqlite3_free(errmsg);
633 }
634 free(querybuf);
635
636 (*cb.cb_func)(NULL, 0, 0, NULL, NULL, NULL, cb.void_arg);
637 }