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