Commit | Line | Data |
---|---|---|
d9898ee8 | 1 | /* |
b0322a85 | 2 | ** Copyright 2000-2010 Double Precision, Inc. See COPYING for |
d9898ee8 | 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 <mysql.h> | |
14 | #include <time.h> | |
15 | ||
16 | #include "authmysql.h" | |
17 | #include "authmysqlrc.h" | |
18 | #include "auth.h" | |
19 | #include "courierauthdebug.h" | |
20 | ||
21 | #define err courier_auth_err | |
22 | ||
d9898ee8 | 23 | static const char *read_env(const char *env) |
24 | { | |
b0322a85 CE |
25 | return authgetconfig(AUTHMYSQLRC, env); |
26 | } | |
d9898ee8 | 27 | |
b0322a85 | 28 | static MYSQL mysql_buf; |
d9898ee8 | 29 | |
b0322a85 | 30 | static MYSQL *mysql=0; |
d9898ee8 | 31 | |
b0322a85 CE |
32 | static char *escape_str(const char *c, size_t n) |
33 | { | |
34 | char *buf=malloc(n*2+1); | |
d9898ee8 | 35 | |
b0322a85 CE |
36 | if (!buf) |
37 | { | |
38 | perror("malloc"); | |
39 | return NULL; | |
d9898ee8 | 40 | } |
41 | ||
b0322a85 CE |
42 | mysql_real_escape_string(mysql, buf, c, n); |
43 | return buf; | |
d9898ee8 | 44 | } |
45 | ||
ac40fd9e | 46 | static void set_session_options(void) |
47 | /* | |
48 | * session variables can be set once for the whole session | |
49 | */ | |
50 | { | |
51 | /* Anton Dobkin <anton@viansib.ru>, VIAN, Ltd. */ | |
52 | #if MYSQL_VERSION_ID >= 41000 | |
53 | const char *character_set=read_env("MYSQL_CHARACTER_SET"), *check; | |
54 | ||
55 | if(character_set){ | |
56 | ||
57 | /* | |
58 | * This function works like the SET NAMES statement, but also sets | |
59 | * the value of mysql->charset, and thus affects the character set | |
60 | * used by mysql_real_escape_string() | |
61 | * | |
62 | * (return value apparently work the opposite of what is documented) | |
63 | */ | |
64 | mysql_set_character_set(mysql, character_set); | |
65 | check = mysql_character_set_name(mysql); | |
66 | if (strcmp(character_set, check) != 0) | |
67 | { | |
68 | err("Cannot set MySQL character set \"%s\", working with \"%s\"\n", | |
69 | character_set, check); | |
70 | } | |
71 | else | |
72 | { | |
73 | DPRINTF("Install of a character set for MySQL: %s", character_set); | |
74 | } | |
75 | } | |
76 | #endif /* 41000 */ | |
77 | } | |
78 | ||
d9898ee8 | 79 | static int do_connect() |
80 | { | |
81 | const char *server; | |
82 | const char *userid; | |
83 | const char *password; | |
84 | const char *database; | |
85 | const char *server_socket=0; | |
86 | unsigned int server_port=0; | |
87 | unsigned int server_opt=0; | |
88 | const char *p; | |
89 | ||
90 | const char *sslkey; | |
91 | const char *sslcert; | |
92 | const char *sslcacert; | |
93 | const char *sslcapath; | |
94 | const char *sslcipher; | |
95 | unsigned int use_ssl=0; | |
96 | ||
97 | /* | |
98 | ** Periodically detect dead connections. | |
99 | */ | |
100 | if (mysql) | |
101 | { | |
102 | static time_t last_time=0; | |
103 | time_t t_check; | |
104 | ||
105 | time(&t_check); | |
106 | ||
107 | if (t_check < last_time) | |
108 | last_time=t_check; /* System clock changed */ | |
109 | ||
110 | if (t_check < last_time + 60) | |
111 | return (0); | |
112 | ||
113 | last_time=t_check; | |
114 | ||
115 | if (mysql_ping(mysql) == 0) return (0); | |
116 | ||
117 | DPRINTF("authmysqllib: mysql_ping failed, connection lost"); | |
118 | mysql_close(mysql); | |
119 | mysql=0; | |
120 | } | |
121 | ||
122 | server=read_env("MYSQL_SERVER"); | |
123 | userid=read_env("MYSQL_USERNAME"); | |
124 | password=read_env("MYSQL_PASSWORD"); | |
125 | database=read_env("MYSQL_DATABASE"); | |
126 | ||
127 | #if MYSQL_VERSION_ID >= 32200 | |
128 | sslkey=read_env("MYSQL_SSL_KEY"); | |
129 | sslcert=read_env("MYSQL_SSL_CERT"); | |
130 | sslcacert=read_env("MYSQL_SSL_CACERT"); | |
131 | sslcapath=read_env("MYSQL_SSL_CAPATH"); | |
132 | sslcipher=read_env("MYSQL_SSL_CIPHER"); | |
133 | ||
134 | if ((sslcert != NULL) && ((sslcacert != NULL) || (sslcapath != NULL))) | |
135 | { | |
136 | use_ssl=1; | |
137 | } | |
138 | #endif | |
139 | ||
140 | server_socket=(char *) read_env("MYSQL_SOCKET"); | |
141 | ||
142 | if ((p=read_env("MYSQL_PORT")) != 0) | |
143 | { | |
144 | server_port=(unsigned int) atoi(p); | |
145 | } | |
146 | ||
147 | if ((p=read_env("MYSQL_OPT")) != 0) | |
148 | { | |
149 | server_opt=(unsigned int) atol(p); | |
150 | } | |
151 | ||
152 | if (!server && !server_socket) | |
153 | { | |
154 | err("authmysql: MYSQL_SERVER nor MYSQL_SOCKET set in" | |
155 | AUTHMYSQLRC "."); | |
156 | return (-1); | |
157 | } | |
158 | ||
159 | if (!userid) | |
160 | { | |
161 | err("authmysql: MYSQL_USERNAME not set in " | |
162 | AUTHMYSQLRC "."); | |
163 | return (-1); | |
164 | } | |
165 | ||
166 | if (!database) | |
167 | { | |
168 | err("authmysql: MYSQL_DATABASE not set in " | |
169 | AUTHMYSQLRC "."); | |
170 | return (-1); | |
171 | } | |
172 | ||
173 | #if MYSQL_VERSION_ID >= 32200 | |
174 | mysql_init(&mysql_buf); | |
175 | if (use_ssl) | |
176 | { | |
177 | mysql_ssl_set(&mysql_buf, sslkey, sslcert, sslcacert, | |
178 | sslcapath, sslcipher); | |
179 | } | |
180 | mysql=mysql_real_connect(&mysql_buf, server, userid, password, | |
181 | NULL, | |
182 | server_port, | |
183 | server_socket, | |
184 | server_opt); | |
185 | #else | |
186 | mysql=mysql_connect(&mysql_buf, server, userid, password); | |
187 | #endif | |
188 | if (!mysql) | |
189 | { | |
190 | err("failed to connect to mysql server (server=%s, userid=%s): %s", | |
191 | server ? server : "<null>", | |
192 | userid ? userid : "<null>", | |
193 | mysql_error(&mysql_buf)); | |
194 | return (-1); | |
195 | } | |
196 | ||
197 | if (mysql_select_db(mysql, database)) | |
198 | { | |
199 | err("authmysql: mysql_select_db(%s) error: %s", | |
200 | database, mysql_error(mysql)); | |
201 | mysql_close(mysql); | |
202 | mysql=0; | |
203 | return (-1); | |
204 | } | |
ac40fd9e | 205 | |
206 | DPRINTF("authmysqllib: connected. Versions: " | |
207 | "header %lu, " | |
208 | "client %lu, " | |
209 | "server %lu", | |
210 | (long)MYSQL_VERSION_ID, | |
211 | mysql_get_client_version(), | |
212 | mysql_get_server_version(mysql)); | |
213 | ||
214 | set_session_options(); | |
d9898ee8 | 215 | return (0); |
216 | } | |
217 | ||
218 | void auth_mysql_cleanup() | |
219 | { | |
220 | if (mysql) | |
221 | { | |
222 | mysql_close(mysql); | |
223 | mysql=0; | |
224 | } | |
225 | } | |
226 | ||
227 | static struct authmysqluserinfo ui={0, 0, 0, 0, 0, 0, 0, 0}; | |
228 | ||
229 | static void initui() | |
230 | { | |
231 | ||
232 | if (ui.username) | |
233 | free(ui.username); | |
234 | if (ui.cryptpw) | |
235 | free(ui.cryptpw); | |
236 | if (ui.clearpw) | |
237 | free(ui.clearpw); | |
238 | if (ui.home) | |
239 | free(ui.home); | |
240 | if (ui.maildir) | |
241 | free(ui.maildir); | |
242 | if (ui.quota) | |
243 | free(ui.quota); | |
244 | if (ui.fullname) | |
245 | free(ui.fullname); | |
246 | if (ui.options) | |
247 | free(ui.options); | |
248 | memset(&ui, 0, sizeof(ui)); | |
249 | } | |
250 | ||
d9898ee8 | 251 | struct authmysqluserinfo *auth_mysql_getuserinfo(const char *username, |
252 | const char *service) | |
253 | { | |
254 | const char *defdomain =NULL; | |
ac40fd9e | 255 | char *querybuf; |
d9898ee8 | 256 | MYSQL_ROW row; |
257 | MYSQL_RES *result; | |
258 | int num_fields; | |
259 | char *endp; | |
260 | ||
261 | const char *select_clause; /* siefca@pld.org.pl */ | |
262 | ||
ac40fd9e | 263 | #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", \ |
264 | login_field, crypt_field, clear_field, uid_field,\ | |
265 | gid_field, home_field, maildir_field, quota_field,\ | |
266 | name_field, options_field, user_table, login_field,\ | |
267 | username_escaped,\ | |
268 | has_domain || !*defdomain ? "":"@", has_domain ? "":defdomain, \ | |
269 | *where_clause ? " AND (":"", where_clause,\ | |
270 | *where_clause ? ")":"" | |
d9898ee8 | 271 | |
272 | if (do_connect()) return (0); | |
273 | ||
274 | initui(); | |
275 | ||
276 | select_clause=read_env("MYSQL_SELECT_CLAUSE"); | |
277 | defdomain=read_env("DEFAULT_DOMAIN"); | |
278 | if (!defdomain) defdomain=""; | |
279 | ||
280 | if (!select_clause) /* siefca@pld.org.pl */ | |
281 | { | |
282 | const char *user_table, | |
283 | *crypt_field, | |
284 | *clear_field, | |
285 | *name_field, | |
286 | *uid_field, | |
287 | *gid_field, | |
288 | *login_field, | |
289 | *home_field, | |
290 | *maildir_field, | |
291 | *quota_field, | |
292 | *options_field, | |
293 | *where_clause; | |
ac40fd9e | 294 | char *username_escaped; |
295 | size_t query_size; | |
296 | char dummy_buf[1]; | |
297 | int has_domain; | |
d9898ee8 | 298 | |
299 | user_table=read_env("MYSQL_USER_TABLE"); | |
300 | ||
301 | if (!user_table) | |
302 | { | |
303 | err("authmysql: MYSQL_USER_TABLE not set in " | |
304 | AUTHMYSQLRC "."); | |
305 | return (0); | |
306 | } | |
307 | ||
308 | crypt_field=read_env("MYSQL_CRYPT_PWFIELD"); | |
309 | clear_field=read_env("MYSQL_CLEAR_PWFIELD"); | |
310 | name_field=read_env("MYSQL_NAME_FIELD"); | |
311 | ||
312 | if (!crypt_field && !clear_field) | |
313 | { | |
314 | err("authmysql: MYSQL_CRYPT_PWFIELD and " | |
315 | "MYSQL_CLEAR_PWFIELD not set in " AUTHMYSQLRC "."); | |
316 | return (0); | |
317 | } | |
318 | if (!crypt_field) crypt_field="\"\""; | |
319 | if (!clear_field) clear_field="\"\""; | |
320 | if (!name_field) name_field="\"\""; | |
321 | ||
322 | uid_field = read_env("MYSQL_UID_FIELD"); | |
323 | if (!uid_field) uid_field = "uid"; | |
324 | ||
325 | gid_field = read_env("MYSQL_GID_FIELD"); | |
326 | if (!gid_field) gid_field = "gid"; | |
327 | ||
328 | login_field = read_env("MYSQL_LOGIN_FIELD"); | |
329 | if (!login_field) login_field = "id"; | |
330 | ||
331 | home_field = read_env("MYSQL_HOME_FIELD"); | |
332 | if (!home_field) home_field = "home"; | |
333 | ||
334 | maildir_field=read_env(service && strcmp(service, "courier")==0 | |
335 | ? "MYSQL_DEFAULTDELIVERY" | |
336 | : "MYSQL_MAILDIR_FIELD"); | |
337 | if (!maildir_field) maildir_field="\"\""; | |
338 | ||
339 | quota_field=read_env("MYSQL_QUOTA_FIELD"); | |
340 | if (!quota_field) quota_field="\"\""; | |
341 | ||
342 | options_field=read_env("MYSQL_AUXOPTIONS_FIELD"); | |
343 | if (!options_field) options_field="\"\""; | |
344 | ||
345 | where_clause=read_env("MYSQL_WHERE_CLAUSE"); | |
346 | if (!where_clause) where_clause = ""; | |
347 | ||
ac40fd9e | 348 | username_escaped=malloc(strlen(username)*2+1); |
d9898ee8 | 349 | |
ac40fd9e | 350 | if (!username_escaped) |
d9898ee8 | 351 | { |
352 | perror("malloc"); | |
353 | return (0); | |
354 | } | |
355 | ||
ac40fd9e | 356 | mysql_real_escape_string(mysql, username_escaped, |
357 | username, strlen(username)); | |
d9898ee8 | 358 | |
ac40fd9e | 359 | has_domain=strchr(username, '@') != NULL; |
d9898ee8 | 360 | |
ac40fd9e | 361 | query_size=snprintf(dummy_buf, 1, DEFAULT_SELECT_QUERY); |
362 | ||
363 | querybuf=malloc(query_size+1); | |
364 | ||
365 | if (!querybuf) | |
366 | { | |
367 | free(username_escaped); | |
368 | perror("malloc"); | |
369 | return(0); | |
d9898ee8 | 370 | } |
ac40fd9e | 371 | |
372 | snprintf(querybuf, query_size+1, DEFAULT_SELECT_QUERY); | |
373 | free(username_escaped); | |
374 | ||
d9898ee8 | 375 | } |
376 | else | |
377 | { | |
378 | /* siefca@pld.org.pl */ | |
b0322a85 CE |
379 | querybuf=auth_parse_select_clause (escape_str, |
380 | select_clause, username, | |
381 | defdomain, service); | |
d9898ee8 | 382 | if (!querybuf) |
383 | { | |
384 | DPRINTF("parse_select_clause failed (DEFAULT_DOMAIN not set?)"); | |
385 | return 0; | |
386 | } | |
387 | } | |
388 | ||
389 | DPRINTF("SQL query: %s", querybuf); | |
390 | if (mysql_query (mysql, querybuf)) | |
391 | { | |
392 | /* <o.blasnik@nextra.de> */ | |
393 | ||
394 | DPRINTF("mysql_query failed, reconnecting: %s", mysql_error(mysql)); | |
395 | auth_mysql_cleanup(); | |
396 | ||
397 | if (do_connect()) | |
398 | { | |
399 | free(querybuf); | |
400 | return (0); | |
401 | } | |
402 | ||
403 | if (mysql_query (mysql, querybuf)) | |
404 | { | |
405 | DPRINTF("mysql_query failed second time, giving up: %s", mysql_error(mysql)); | |
406 | free(querybuf); | |
407 | auth_mysql_cleanup(); | |
408 | /* Server went down, that's OK, | |
409 | ** try again next time. | |
410 | */ | |
411 | return (0); | |
412 | } | |
413 | } | |
414 | free(querybuf); | |
415 | ||
416 | result = mysql_store_result (mysql); | |
417 | if (result) | |
418 | { | |
419 | if (mysql_num_rows(result)) | |
420 | { | |
421 | row = mysql_fetch_row (result); | |
422 | num_fields = mysql_num_fields (result); | |
423 | ||
424 | if (num_fields < 6) | |
425 | { | |
426 | DPRINTF("incomplete row, only %d fields returned", | |
427 | num_fields); | |
428 | mysql_free_result(result); | |
429 | return(0); | |
430 | } | |
431 | ||
432 | if (row[0] && row[0][0]) | |
433 | ui.username=strdup(row[0]); | |
434 | if (row[1] && row[1][0]) | |
435 | ui.cryptpw=strdup(row[1]); | |
436 | if (row[2] && row[2][0]) | |
437 | ui.clearpw=strdup(row[2]); | |
438 | /* perhaps authmysql needs a glob_uid/glob_gid feature | |
439 | like authldap? */ | |
440 | if (!row[3] || !row[3][0] || | |
441 | (ui.uid=strtol(row[3], &endp, 10), endp[0] != '\0')) | |
442 | { | |
443 | DPRINTF("invalid value for uid: '%s'", | |
444 | row[3] ? row[3] : "<null>"); | |
445 | mysql_free_result(result); | |
446 | return 0; | |
447 | } | |
448 | if (!row[4] || !row[4][0] || | |
449 | (ui.gid=strtol(row[4], &endp, 10), endp[0] != '\0')) | |
450 | { | |
451 | DPRINTF("invalid value for gid: '%s'", | |
452 | row[4] ? row[4] : "<null>"); | |
453 | mysql_free_result(result); | |
454 | return 0; | |
455 | } | |
456 | if (row[5] && row[5][0]) | |
457 | ui.home=strdup(row[5]); | |
458 | else | |
459 | { | |
460 | DPRINTF("required value for 'home' (column 6) is missing"); | |
461 | mysql_free_result(result); | |
462 | return(0); | |
463 | } | |
464 | if (num_fields > 6 && row[6] && row[6][0]) | |
465 | ui.maildir=strdup(row[6]); | |
466 | if (num_fields > 7 && row[7] && row[7][0]) | |
467 | ui.quota=strdup(row[7]); | |
468 | if (num_fields > 8 && row[8] && row[8][0]) | |
469 | ui.fullname=strdup(row[8]); | |
470 | if (num_fields > 9 && row[9] && row[9][0]) | |
471 | ui.options=strdup(row[9]); | |
472 | } | |
473 | else | |
474 | { | |
475 | DPRINTF("zero rows returned"); | |
476 | mysql_free_result(result); | |
477 | return (&ui); /* User not found */ | |
478 | } | |
479 | } | |
480 | else | |
481 | { | |
482 | DPRINTF("mysql_store_result failed"); | |
483 | return (0); | |
484 | } | |
485 | mysql_free_result(result); | |
486 | return (&ui); | |
487 | } | |
488 | ||
489 | int auth_mysql_setpass(const char *user, const char *pass, | |
490 | const char *oldpass) | |
491 | { | |
492 | char *newpass_crypt; | |
d9898ee8 | 493 | char *sql_buf; |
d9898ee8 | 494 | int rc=0; |
495 | ||
ac40fd9e | 496 | char *clear_escaped; |
497 | char *crypt_escaped; | |
498 | ||
d9898ee8 | 499 | const char *clear_field =NULL, |
500 | *crypt_field =NULL, | |
501 | *defdomain =NULL, | |
502 | *where_clause =NULL, | |
503 | *user_table =NULL, | |
504 | *login_field =NULL, | |
505 | *chpass_clause =NULL; /* siefca@pld.org.pl */ | |
506 | ||
ac40fd9e | 507 | if (do_connect()) return (-1); |
d9898ee8 | 508 | |
509 | if (!(newpass_crypt=authcryptpasswd(pass, oldpass))) | |
510 | return (-1); | |
511 | ||
ac40fd9e | 512 | clear_escaped=malloc(strlen(pass)*2+1); |
513 | ||
514 | if (!clear_escaped) | |
d9898ee8 | 515 | { |
ac40fd9e | 516 | perror("malloc"); |
517 | free(newpass_crypt); | |
518 | return -1; | |
d9898ee8 | 519 | } |
520 | ||
ac40fd9e | 521 | crypt_escaped=malloc(strlen(newpass_crypt)*2+1); |
522 | ||
523 | if (!crypt_escaped) | |
524 | { | |
525 | perror("malloc"); | |
526 | free(clear_escaped); | |
527 | free(newpass_crypt); | |
528 | return -1; | |
529 | } | |
530 | ||
531 | mysql_real_escape_string(mysql, clear_escaped, pass, strlen(pass)); | |
532 | mysql_real_escape_string(mysql, crypt_escaped, | |
533 | newpass_crypt, strlen(newpass_crypt)); | |
534 | ||
d9898ee8 | 535 | /* siefca@pld.org.pl */ |
536 | chpass_clause=read_env("MYSQL_CHPASS_CLAUSE"); | |
537 | defdomain=read_env("DEFAULT_DOMAIN"); | |
538 | user_table=read_env("MYSQL_USER_TABLE"); | |
539 | if (!chpass_clause) | |
540 | { | |
ac40fd9e | 541 | int has_domain=strchr(user, '@') != NULL; |
542 | char *username_escaped; | |
543 | char dummy_buf[1]; | |
544 | size_t sql_buf_size; | |
545 | ||
546 | username_escaped=malloc(strlen(user)*2+1); | |
547 | ||
548 | if (!username_escaped) | |
549 | { | |
550 | perror("malloc"); | |
551 | free(clear_escaped); | |
552 | free(crypt_escaped); | |
553 | free(newpass_crypt); | |
554 | return -1; | |
555 | } | |
556 | ||
557 | mysql_real_escape_string(mysql, username_escaped, | |
558 | user, strlen(user)); | |
559 | ||
d9898ee8 | 560 | login_field = read_env("MYSQL_LOGIN_FIELD"); |
561 | if (!login_field) login_field = "id"; | |
562 | crypt_field=read_env("MYSQL_CRYPT_PWFIELD"); | |
563 | clear_field=read_env("MYSQL_CLEAR_PWFIELD"); | |
564 | where_clause=read_env("MYSQL_WHERE_CLAUSE"); | |
d9898ee8 | 565 | |
ac40fd9e | 566 | if (!where_clause) |
567 | where_clause=""; | |
d9898ee8 | 568 | |
ac40fd9e | 569 | if (!crypt_field) |
570 | crypt_field=""; | |
d9898ee8 | 571 | |
ac40fd9e | 572 | if (!clear_field) |
573 | clear_field=""; | |
d9898ee8 | 574 | |
b0322a85 CE |
575 | if (!defdomain) |
576 | defdomain=""; | |
d9898ee8 | 577 | |
ac40fd9e | 578 | #define DEFAULT_SETPASS_UPDATE \ |
579 | "UPDATE %s SET %s%s%s%s %s %s%s%s%s WHERE %s='%s%s%s' %s%s%s", \ | |
580 | user_table, \ | |
581 | *clear_field ? clear_field:"", \ | |
582 | *clear_field ? "='":"", \ | |
583 | *clear_field ? clear_escaped:"", \ | |
584 | *clear_field ? "'":"", \ | |
585 | \ | |
586 | *clear_field && *crypt_field ? ",":"", \ | |
587 | \ | |
588 | *crypt_field ? crypt_field:"", \ | |
589 | *crypt_field ? "='":"", \ | |
590 | *crypt_field ? crypt_escaped:"", \ | |
591 | *crypt_field ? "'":"", \ | |
592 | login_field, \ | |
593 | username_escaped, \ | |
594 | has_domain || !*defdomain ? "":"@", \ | |
595 | has_domain ? "":defdomain, \ | |
596 | *where_clause ? " AND (":"", where_clause, \ | |
597 | *where_clause ? ")":"" | |
d9898ee8 | 598 | |
d9898ee8 | 599 | |
ac40fd9e | 600 | sql_buf_size=snprintf(dummy_buf, 1, DEFAULT_SETPASS_UPDATE); |
d9898ee8 | 601 | |
ac40fd9e | 602 | sql_buf=malloc(sql_buf_size+1); |
d9898ee8 | 603 | |
ac40fd9e | 604 | if (sql_buf) |
605 | snprintf(sql_buf, sql_buf_size+1, | |
606 | DEFAULT_SETPASS_UPDATE); | |
d9898ee8 | 607 | |
ac40fd9e | 608 | free(username_escaped); |
d9898ee8 | 609 | } |
610 | else | |
611 | { | |
b0322a85 CE |
612 | sql_buf=auth_parse_chpass_clause(escape_str, |
613 | chpass_clause, | |
614 | user, | |
615 | defdomain, | |
616 | clear_escaped, | |
617 | crypt_escaped); | |
d9898ee8 | 618 | } |
ac40fd9e | 619 | |
620 | free(clear_escaped); | |
621 | free(crypt_escaped); | |
622 | free(newpass_crypt); | |
d9898ee8 | 623 | |
624 | if (courier_authdebug_login_level >= 2) | |
625 | { | |
626 | DPRINTF("setpass SQL: %s", sql_buf); | |
627 | } | |
628 | if (mysql_query (mysql, sql_buf)) | |
629 | { | |
630 | DPRINTF("setpass SQL failed"); | |
631 | rc= -1; | |
632 | auth_mysql_cleanup(); | |
633 | } | |
634 | free(sql_buf); | |
635 | return (rc); | |
636 | } | |
637 | ||
638 | void auth_mysql_enumerate( void(*cb_func)(const char *name, | |
639 | uid_t uid, | |
640 | gid_t gid, | |
641 | const char *homedir, | |
642 | const char *maildir, | |
643 | const char *options, | |
644 | void *void_arg), | |
645 | void *void_arg) | |
646 | { | |
647 | const char *defdomain, *select_clause; | |
ac40fd9e | 648 | char *querybuf; |
d9898ee8 | 649 | MYSQL_ROW row; |
650 | MYSQL_RES *result; | |
651 | ||
b0322a85 CE |
652 | if (do_connect()) |
653 | { | |
654 | (*cb_func)(NULL, 0, 0, NULL, NULL, NULL, void_arg); | |
655 | return; | |
656 | } | |
d9898ee8 | 657 | |
658 | initui(); | |
659 | ||
660 | select_clause=read_env("MYSQL_ENUMERATE_CLAUSE"); | |
661 | defdomain=read_env("DEFAULT_DOMAIN"); | |
662 | if (!defdomain || !defdomain[0]) | |
663 | defdomain="*"; /* otherwise parse_select_clause fails */ | |
664 | ||
665 | if (!select_clause) | |
666 | { | |
667 | const char *user_table, | |
668 | *uid_field, | |
669 | *gid_field, | |
670 | *login_field, | |
671 | *home_field, | |
672 | *maildir_field, | |
673 | *options_field, | |
674 | *where_clause; | |
ac40fd9e | 675 | char dummy_buf[1]; |
676 | size_t query_len; | |
d9898ee8 | 677 | |
678 | user_table=read_env("MYSQL_USER_TABLE"); | |
679 | ||
680 | if (!user_table) | |
681 | { | |
682 | err("authmysql: MYSQL_USER_TABLE not set in " | |
683 | AUTHMYSQLRC "."); | |
684 | return; | |
685 | } | |
686 | ||
687 | uid_field = read_env("MYSQL_UID_FIELD"); | |
688 | if (!uid_field) uid_field = "uid"; | |
689 | ||
690 | gid_field = read_env("MYSQL_GID_FIELD"); | |
691 | if (!gid_field) gid_field = "gid"; | |
692 | ||
693 | login_field = read_env("MYSQL_LOGIN_FIELD"); | |
694 | if (!login_field) login_field = "id"; | |
695 | ||
696 | home_field = read_env("MYSQL_HOME_FIELD"); | |
697 | if (!home_field) home_field = "home"; | |
698 | ||
699 | maildir_field=read_env("MYSQL_MAILDIR_FIELD"); | |
700 | if (!maildir_field) maildir_field="\"\""; | |
701 | ||
702 | options_field=read_env("MYSQL_AUXOPTIONS_FIELD"); | |
703 | if (!options_field) options_field="\"\""; | |
704 | ||
705 | where_clause=read_env("MYSQL_WHERE_CLAUSE"); | |
706 | if (!where_clause) where_clause = ""; | |
707 | ||
ac40fd9e | 708 | |
709 | #define DEFAULT_ENUMERATE_QUERY \ | |
710 | "SELECT %s, %s, %s, %s, %s, %s FROM %s %s%s",\ | |
711 | login_field, uid_field, gid_field, \ | |
712 | home_field, maildir_field, \ | |
713 | options_field, user_table, \ | |
714 | *where_clause ? " WHERE ":"", \ | |
715 | where_clause | |
716 | ||
717 | query_len=snprintf(dummy_buf, 1, DEFAULT_ENUMERATE_QUERY); | |
718 | ||
719 | querybuf=malloc(query_len+1); | |
d9898ee8 | 720 | |
721 | if (!querybuf) | |
722 | { | |
723 | perror("malloc"); | |
724 | return; | |
725 | } | |
726 | ||
ac40fd9e | 727 | snprintf(querybuf, query_len+1, DEFAULT_ENUMERATE_QUERY); |
d9898ee8 | 728 | } |
729 | else | |
730 | { | |
731 | /* siefca@pld.org.pl */ | |
b0322a85 CE |
732 | querybuf=auth_parse_select_clause (escape_str, |
733 | select_clause, "*", | |
734 | defdomain, "enumerate"); | |
d9898ee8 | 735 | if (!querybuf) |
736 | { | |
737 | DPRINTF("authmysql: parse_select_clause failed"); | |
738 | return; | |
739 | } | |
740 | } | |
741 | DPRINTF("authmysql: enumerate query: %s", querybuf); | |
742 | ||
743 | if (mysql_query (mysql, querybuf)) | |
744 | { | |
745 | DPRINTF("mysql_query failed, reconnecting: %s", mysql_error(mysql)); | |
746 | /* <o.blasnik@nextra.de> */ | |
747 | ||
748 | auth_mysql_cleanup(); | |
749 | ||
750 | if (do_connect()) | |
751 | { | |
752 | free(querybuf); | |
753 | return; | |
754 | } | |
755 | ||
756 | if (mysql_query (mysql, querybuf)) | |
757 | { | |
758 | DPRINTF("mysql_query failed second time, giving up: %s", mysql_error(mysql)); | |
759 | free(querybuf); | |
760 | auth_mysql_cleanup(); | |
761 | return; | |
762 | } | |
763 | } | |
764 | free(querybuf); | |
765 | ||
766 | result = mysql_use_result (mysql); | |
767 | if (result) | |
768 | { | |
769 | const char *username; | |
770 | uid_t uid; | |
771 | gid_t gid; | |
772 | const char *homedir; | |
773 | const char *maildir; | |
774 | const char *options; | |
775 | ||
776 | while ((row = mysql_fetch_row (result)) != NULL) | |
777 | { | |
778 | if(!row[0] || !row[0][0] | |
ac40fd9e | 779 | || !row[1] || !row[1][0] |
780 | || !row[2] || !row[2][0] | |
781 | || !row[3] || !row[3][0]) | |
d9898ee8 | 782 | { |
783 | continue; | |
784 | } | |
785 | ||
786 | username=row[0]; | |
787 | uid=atol(row[1]); /* FIXME use strtol to validate */ | |
788 | gid=atol(row[2]); | |
789 | homedir=row[3]; | |
790 | maildir=row[4]; | |
791 | options=row[5]; | |
792 | ||
793 | if (maildir && !*maildir) | |
794 | maildir=NULL; | |
795 | ||
796 | (*cb_func)(username, uid, gid, homedir, | |
797 | maildir, options, void_arg); | |
798 | } | |
799 | } | |
800 | /* NULL row could indicate end of result or an error */ | |
801 | if (mysql_errno(mysql)) | |
802 | { | |
803 | DPRINTF("mysql error during enumeration: %s", mysql_error(mysql)); | |
804 | } | |
805 | else | |
806 | (*cb_func)(NULL, 0, 0, NULL, NULL, NULL, void_arg); | |
807 | ||
808 | if (result) mysql_free_result(result); | |
809 | } |