2 ** Copyright 2000-2008 Double Precision, Inc. See COPYING for
3 ** distribution information.
11 #include <sys/types.h>
16 #include "authmysql.h"
17 #include "authmysqlrc.h"
19 #include "courierauthdebug.h"
21 #define err courier_auth_err
23 /* siefca@pld.org.pl */
24 #define MAX_SUBSTITUTION_LEN 32
25 #define SV_BEGIN_MARK "$("
26 #define SV_END_MARK ")"
27 #define SV_BEGIN_LEN ((sizeof(SV_BEGIN_MARK))-1)
28 #define SV_END_LEN ((sizeof(SV_END_MARK))-1)
30 static const char rcsid
[]="$Id: authmysqllib.c,v 1.49 2008/06/08 16:40:36 mrsam Exp $";
32 /* siefca@pld.org.pl */
40 /* siefca@pld.org.pl */
41 typedef int (*parsefunc
)(const char *, size_t, void *);
43 static const char *read_env(const char *env
)
45 static char *mysqlauth
=0;
46 static size_t mysqlauth_size
=0;
53 FILE *f
=fopen(AUTHMYSQLRC
, "r");
57 if (fstat(fileno(f
), &buf
) ||
58 (mysqlauth
=malloc(buf
.st_size
+2)) == 0)
63 if (fread(mysqlauth
, buf
.st_size
, 1, f
) != 1)
70 mysqlauth
[mysqlauth_size
=buf
.st_size
]=0;
72 for (i
=0; i
<mysqlauth_size
; i
++)
73 if (mysqlauth
[i
] == '\n')
74 { /* siefca@pld.org.pl */
75 if (!i
|| mysqlauth
[i
-1] != '\\')
81 mysqlauth
[i
]=mysqlauth
[i
-1]= ' ';
87 for (i
=0; i
<mysqlauth_size
; )
90 if (memcmp(p
, env
, l
) == 0 &&
91 isspace((int)(unsigned char)p
[l
]))
94 while (*p
&& *p
!= '\n' &&
95 isspace((int)(unsigned char)*p
))
100 while (i
< mysqlauth_size
)
101 if (mysqlauth
[i
++] == 0) break;
104 if (i
< mysqlauth_size
)
109 static MYSQL mysql_buf
;
111 static MYSQL
*mysql
=0;
113 static void set_session_options(void)
115 * session variables can be set once for the whole session
118 /* Anton Dobkin <anton@viansib.ru>, VIAN, Ltd. */
119 #if MYSQL_VERSION_ID >= 41000
120 const char *character_set
=read_env("MYSQL_CHARACTER_SET"), *check
;
125 * This function works like the SET NAMES statement, but also sets
126 * the value of mysql->charset, and thus affects the character set
127 * used by mysql_real_escape_string()
129 * (return value apparently work the opposite of what is documented)
131 mysql_set_character_set(mysql
, character_set
);
132 check
= mysql_character_set_name(mysql
);
133 if (strcmp(character_set
, check
) != 0)
135 err("Cannot set MySQL character set \"%s\", working with \"%s\"\n",
136 character_set
, check
);
140 DPRINTF("Install of a character set for MySQL: %s", character_set
);
146 static int do_connect()
150 const char *password
;
151 const char *database
;
152 const char *server_socket
=0;
153 unsigned int server_port
=0;
154 unsigned int server_opt
=0;
159 const char *sslcacert
;
160 const char *sslcapath
;
161 const char *sslcipher
;
162 unsigned int use_ssl
=0;
165 ** Periodically detect dead connections.
169 static time_t last_time
=0;
174 if (t_check
< last_time
)
175 last_time
=t_check
; /* System clock changed */
177 if (t_check
< last_time
+ 60)
182 if (mysql_ping(mysql
) == 0) return (0);
184 DPRINTF("authmysqllib: mysql_ping failed, connection lost");
189 server
=read_env("MYSQL_SERVER");
190 userid
=read_env("MYSQL_USERNAME");
191 password
=read_env("MYSQL_PASSWORD");
192 database
=read_env("MYSQL_DATABASE");
194 #if MYSQL_VERSION_ID >= 32200
195 sslkey
=read_env("MYSQL_SSL_KEY");
196 sslcert
=read_env("MYSQL_SSL_CERT");
197 sslcacert
=read_env("MYSQL_SSL_CACERT");
198 sslcapath
=read_env("MYSQL_SSL_CAPATH");
199 sslcipher
=read_env("MYSQL_SSL_CIPHER");
201 if ((sslcert
!= NULL
) && ((sslcacert
!= NULL
) || (sslcapath
!= NULL
)))
207 server_socket
=(char *) read_env("MYSQL_SOCKET");
209 if ((p
=read_env("MYSQL_PORT")) != 0)
211 server_port
=(unsigned int) atoi(p
);
214 if ((p
=read_env("MYSQL_OPT")) != 0)
216 server_opt
=(unsigned int) atol(p
);
219 if (!server
&& !server_socket
)
221 err("authmysql: MYSQL_SERVER nor MYSQL_SOCKET set in"
228 err("authmysql: MYSQL_USERNAME not set in "
235 err("authmysql: MYSQL_DATABASE not set in "
240 #if MYSQL_VERSION_ID >= 32200
241 mysql_init(&mysql_buf
);
244 mysql_ssl_set(&mysql_buf
, sslkey
, sslcert
, sslcacert
,
245 sslcapath
, sslcipher
);
247 mysql
=mysql_real_connect(&mysql_buf
, server
, userid
, password
,
253 mysql
=mysql_connect(&mysql_buf
, server
, userid
, password
);
257 err("failed to connect to mysql server (server=%s, userid=%s): %s",
258 server
? server
: "<null>",
259 userid
? userid
: "<null>",
260 mysql_error(&mysql_buf
));
264 if (mysql_select_db(mysql
, database
))
266 err("authmysql: mysql_select_db(%s) error: %s",
267 database
, mysql_error(mysql
));
273 DPRINTF("authmysqllib: connected. Versions: "
277 (long)MYSQL_VERSION_ID
,
278 mysql_get_client_version(),
279 mysql_get_server_version(mysql
));
281 set_session_options();
285 void auth_mysql_cleanup()
294 static struct authmysqluserinfo ui
={0, 0, 0, 0, 0, 0, 0, 0};
315 memset(&ui
, 0, sizeof(ui
));
318 /* siefca@pld.org.pl */
319 static struct var_data
*get_variable (const char *begin
, size_t len
,
320 struct var_data
*vdt
)
322 struct var_data
*vdp
;
324 if (!begin
|| !vdt
) /* should never happend */
326 err("authmysql: critical error while "
327 "parsing substitution variable");
332 err("authmysql: unknown empty substitution "
333 "variable - aborting");
336 if (len
> MAX_SUBSTITUTION_LEN
)
338 err("authmysql: variable name too long "
339 "while parsing substitution. "
342 "%.*s...", MAX_SUBSTITUTION_LEN
, begin
);
346 for (vdp
=vdt
; vdp
->name
; vdp
++)
347 if (vdp
->size
== len
+1 &&
348 !strncmp(begin
, vdp
->name
, len
))
352 if (!vdp
->value_length
) /* length cache */
353 vdp
->value_length
= strlen (vdp
->value
);
357 err("authmysql: unknown substitution variable "
366 /* siefca@pld.org.pl */
367 static int ParsePlugin_counter (const char *p
, size_t length
, void *vp
)
369 if (!p
|| !vp
|| length
< 0)
371 err("authmysql: bad arguments while counting "
376 *((size_t *)vp
) += length
;
381 /* siefca@pld.org.pl */
382 static int ParsePlugin_builder (const char *p
, size_t length
, void *vp
)
384 char **strptr
= (char **) vp
;
386 if (!p
|| !vp
|| length
< 0)
388 err("authmysql: bad arguments while building "
393 if (!length
) return 0;
394 memcpy ((void *) *strptr
, (void *) p
, length
);
400 /* siefca@pld.org.pl */
401 static int parse_core (const char *source
, struct var_data
*vdt
,
402 parsefunc outfn
, void *result
)
406 const char *p
, *q
, *e
,
409 struct var_data
*v_ptr
;
415 err("authmysql: no memory allocated for result "
416 "while parser core was invoked");
421 err("authmysql: no substitution table found "
422 "while parser core was invoked");
427 while ( (p
=strstr(q
, SV_BEGIN_MARK
)) )
429 e
= strstr (p
, SV_END_MARK
);
432 err("authmysql: syntax error in "
434 "- no closing symbol found! "
435 "bad variable begins with:"
436 "%.*s...", MAX_SUBSTITUTION_LEN
, p
);
442 ** __________sometext$(variable_name)_________
444 ** t_begin' t_end' `v_begin `v_end
448 v_begin
= p
+SV_BEGIN_LEN
; /* variable field ptr */
449 v_end
= e
-SV_END_LEN
; /* variable field last character */
450 v_size
= v_end
-v_begin
+1;/* variable field length */
452 t_begin
= q
; /* text field ptr */
453 t_end
= p
-1; /* text field last character */
454 t_size
= t_end
-t_begin
+1;/* text field length */
457 if ( (outfn (t_begin
, t_size
, result
)) == -1 )
460 /* work on variable */
461 v_ptr
= get_variable (v_begin
, v_size
, vdt
);
462 if (!v_ptr
) return -1;
464 if ( (outfn (v_ptr
->value
, v_ptr
->value_length
, result
)) == -1 )
470 /* work on last part of text if any */
472 if ( (outfn (q
, strlen(q
), result
)) == -1 )
478 /* siefca@pld.org.pl */
479 static char *parse_string (const char *source
, struct var_data
*vdt
)
481 struct var_data
*vdp
= NULL
;
482 char *output_buf
= NULL
,
486 if (source
== NULL
|| *source
== '\0' ||
487 vdt
== NULL
|| vdt
[0].name
== NULL
)
489 err("authmysql: source clause is empty "
490 "- this is critical error");
494 /* zero var_data length cache - important! */
495 for (vdp
=vdt
; vdp
->name
; vdp
++)
496 vdp
->value_length
= 0;
499 /* phase 1 - count and validate string */
500 if ( (parse_core (source
, vdt
, &ParsePlugin_counter
, &buf_size
)) != 0)
503 /* phase 2 - allocate memory */
504 output_buf
= malloc (buf_size
);
510 pass_buf
= output_buf
;
512 /* phase 3 - build the output string */
513 if ( (parse_core (source
, vdt
, &ParsePlugin_builder
, &pass_buf
)) != 0)
523 static char *local_part_escaped(const char *username
)
525 const char *p
=strchr(username
, '@');
526 size_t n
=p
? p
-username
:strlen(username
);
527 char *buf
=malloc(n
*2+1);
535 mysql_real_escape_string(mysql
, buf
, username
, n
);
539 static char *domain_part_escaped(const char *username
,
540 const char *defdomain
)
542 const char *p
=strchr(username
, '@');
561 mysql_real_escape_string(mysql
, buf
, p
, n
);
565 static int local_and_domain_part_escaped(const char *username
,
566 const char *defdomain
,
570 if ((*local_ret
=local_part_escaped(username
)) == NULL
)
573 if ((*domain_ret
=domain_part_escaped(username
, defdomain
)) == NULL
)
582 /* siefca@pld.org.pl */
583 static char *parse_select_clause (const char *clause
, const char *username
,
584 const char *defdomain
,
589 static struct var_data vd
[]={
590 {"local_part", NULL
, sizeof("local_part"), 0},
591 {"domain", NULL
, sizeof("domain"), 0},
592 {"service", NULL
, sizeof("service"), 0},
598 if (clause
== NULL
|| *clause
== '\0' ||
599 !username
|| *username
== '\0')
602 if (!local_and_domain_part_escaped(username
, defdomain
,
608 vd
[2].value
= service
;
610 str
=parse_string (clause
, vd
);
616 /* siefca@pld.org.pl */
617 static char *parse_chpass_clause (const char *clause
, const char *username
,
618 const char *defdomain
, const char *newpass
,
619 const char *newpass_crypt
)
623 static struct var_data vd
[]={
624 {"local_part", NULL
, sizeof("local_part"), 0},
625 {"domain", NULL
, sizeof("domain"), 0},
626 {"newpass", NULL
, sizeof("newpass"), 0},
627 {"newpass_crypt", NULL
, sizeof("newpass_crypt"), 0},
632 if (clause
== NULL
|| *clause
== '\0' ||
633 !username
|| *username
== '\0' ||
634 !newpass
|| *newpass
== '\0' ||
635 !newpass_crypt
|| *newpass_crypt
== '\0') return NULL
;
637 if (!local_and_domain_part_escaped(username
, defdomain
,
643 vd
[2].value
= newpass
;
644 vd
[3].value
= newpass_crypt
;
646 if (!vd
[0].value
|| !vd
[1].value
||
647 !vd
[2].value
|| !vd
[3].value
)
654 str
=parse_string (clause
, vd
);
660 struct authmysqluserinfo
*auth_mysql_getuserinfo(const char *username
,
663 const char *defdomain
=NULL
;
670 const char *select_clause
; /* siefca@pld.org.pl */
672 #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", \
673 login_field, crypt_field, clear_field, uid_field,\
674 gid_field, home_field, maildir_field, quota_field,\
675 name_field, options_field, user_table, login_field,\
677 has_domain || !*defdomain ? "":"@", has_domain ? "":defdomain, \
678 *where_clause ? " AND (":"", where_clause,\
679 *where_clause ? ")":""
681 if (do_connect()) return (0);
685 select_clause
=read_env("MYSQL_SELECT_CLAUSE");
686 defdomain
=read_env("DEFAULT_DOMAIN");
687 if (!defdomain
) defdomain
="";
689 if (!select_clause
) /* siefca@pld.org.pl */
691 const char *user_table
,
703 char *username_escaped
;
708 user_table
=read_env("MYSQL_USER_TABLE");
712 err("authmysql: MYSQL_USER_TABLE not set in "
717 crypt_field
=read_env("MYSQL_CRYPT_PWFIELD");
718 clear_field
=read_env("MYSQL_CLEAR_PWFIELD");
719 name_field
=read_env("MYSQL_NAME_FIELD");
721 if (!crypt_field
&& !clear_field
)
723 err("authmysql: MYSQL_CRYPT_PWFIELD and "
724 "MYSQL_CLEAR_PWFIELD not set in " AUTHMYSQLRC
".");
727 if (!crypt_field
) crypt_field
="\"\"";
728 if (!clear_field
) clear_field
="\"\"";
729 if (!name_field
) name_field
="\"\"";
731 uid_field
= read_env("MYSQL_UID_FIELD");
732 if (!uid_field
) uid_field
= "uid";
734 gid_field
= read_env("MYSQL_GID_FIELD");
735 if (!gid_field
) gid_field
= "gid";
737 login_field
= read_env("MYSQL_LOGIN_FIELD");
738 if (!login_field
) login_field
= "id";
740 home_field
= read_env("MYSQL_HOME_FIELD");
741 if (!home_field
) home_field
= "home";
743 maildir_field
=read_env(service
&& strcmp(service
, "courier")==0
744 ? "MYSQL_DEFAULTDELIVERY"
745 : "MYSQL_MAILDIR_FIELD");
746 if (!maildir_field
) maildir_field
="\"\"";
748 quota_field
=read_env("MYSQL_QUOTA_FIELD");
749 if (!quota_field
) quota_field
="\"\"";
751 options_field
=read_env("MYSQL_AUXOPTIONS_FIELD");
752 if (!options_field
) options_field
="\"\"";
754 where_clause
=read_env("MYSQL_WHERE_CLAUSE");
755 if (!where_clause
) where_clause
= "";
757 username_escaped
=malloc(strlen(username
)*2+1);
759 if (!username_escaped
)
765 mysql_real_escape_string(mysql
, username_escaped
,
766 username
, strlen(username
));
768 has_domain
=strchr(username
, '@') != NULL
;
770 query_size
=snprintf(dummy_buf
, 1, DEFAULT_SELECT_QUERY
);
772 querybuf
=malloc(query_size
+1);
776 free(username_escaped
);
781 snprintf(querybuf
, query_size
+1, DEFAULT_SELECT_QUERY
);
782 free(username_escaped
);
787 /* siefca@pld.org.pl */
788 querybuf
=parse_select_clause (select_clause
, username
,
792 DPRINTF("parse_select_clause failed (DEFAULT_DOMAIN not set?)");
797 DPRINTF("SQL query: %s", querybuf
);
798 if (mysql_query (mysql
, querybuf
))
800 /* <o.blasnik@nextra.de> */
802 DPRINTF("mysql_query failed, reconnecting: %s", mysql_error(mysql
));
803 auth_mysql_cleanup();
811 if (mysql_query (mysql
, querybuf
))
813 DPRINTF("mysql_query failed second time, giving up: %s", mysql_error(mysql
));
815 auth_mysql_cleanup();
816 /* Server went down, that's OK,
817 ** try again next time.
824 result
= mysql_store_result (mysql
);
827 if (mysql_num_rows(result
))
829 row
= mysql_fetch_row (result
);
830 num_fields
= mysql_num_fields (result
);
834 DPRINTF("incomplete row, only %d fields returned",
836 mysql_free_result(result
);
840 if (row
[0] && row
[0][0])
841 ui
.username
=strdup(row
[0]);
842 if (row
[1] && row
[1][0])
843 ui
.cryptpw
=strdup(row
[1]);
844 if (row
[2] && row
[2][0])
845 ui
.clearpw
=strdup(row
[2]);
846 /* perhaps authmysql needs a glob_uid/glob_gid feature
848 if (!row
[3] || !row
[3][0] ||
849 (ui
.uid
=strtol(row
[3], &endp
, 10), endp
[0] != '\0'))
851 DPRINTF("invalid value for uid: '%s'",
852 row
[3] ? row
[3] : "<null>");
853 mysql_free_result(result
);
856 if (!row
[4] || !row
[4][0] ||
857 (ui
.gid
=strtol(row
[4], &endp
, 10), endp
[0] != '\0'))
859 DPRINTF("invalid value for gid: '%s'",
860 row
[4] ? row
[4] : "<null>");
861 mysql_free_result(result
);
864 if (row
[5] && row
[5][0])
865 ui
.home
=strdup(row
[5]);
868 DPRINTF("required value for 'home' (column 6) is missing");
869 mysql_free_result(result
);
872 if (num_fields
> 6 && row
[6] && row
[6][0])
873 ui
.maildir
=strdup(row
[6]);
874 if (num_fields
> 7 && row
[7] && row
[7][0])
875 ui
.quota
=strdup(row
[7]);
876 if (num_fields
> 8 && row
[8] && row
[8][0])
877 ui
.fullname
=strdup(row
[8]);
878 if (num_fields
> 9 && row
[9] && row
[9][0])
879 ui
.options
=strdup(row
[9]);
883 DPRINTF("zero rows returned");
884 mysql_free_result(result
);
885 return (&ui
); /* User not found */
890 DPRINTF("mysql_store_result failed");
893 mysql_free_result(result
);
897 int auth_mysql_setpass(const char *user
, const char *pass
,
907 const char *clear_field
=NULL
,
913 *chpass_clause
=NULL
; /* siefca@pld.org.pl */
915 if (do_connect()) return (-1);
917 if (!(newpass_crypt
=authcryptpasswd(pass
, oldpass
)))
920 clear_escaped
=malloc(strlen(pass
)*2+1);
929 crypt_escaped
=malloc(strlen(newpass_crypt
)*2+1);
939 mysql_real_escape_string(mysql
, clear_escaped
, pass
, strlen(pass
));
940 mysql_real_escape_string(mysql
, crypt_escaped
,
941 newpass_crypt
, strlen(newpass_crypt
));
943 /* siefca@pld.org.pl */
944 chpass_clause
=read_env("MYSQL_CHPASS_CLAUSE");
945 defdomain
=read_env("DEFAULT_DOMAIN");
946 user_table
=read_env("MYSQL_USER_TABLE");
949 int has_domain
=strchr(user
, '@') != NULL
;
950 char *username_escaped
;
954 username_escaped
=malloc(strlen(user
)*2+1);
956 if (!username_escaped
)
965 mysql_real_escape_string(mysql
, username_escaped
,
968 login_field
= read_env("MYSQL_LOGIN_FIELD");
969 if (!login_field
) login_field
= "id";
970 crypt_field
=read_env("MYSQL_CRYPT_PWFIELD");
971 clear_field
=read_env("MYSQL_CLEAR_PWFIELD");
972 where_clause
=read_env("MYSQL_WHERE_CLAUSE");
984 #define DEFAULT_SETPASS_UPDATE \
985 "UPDATE %s SET %s%s%s%s %s %s%s%s%s WHERE %s='%s%s%s' %s%s%s", \
987 *clear_field ? clear_field:"", \
988 *clear_field ? "='":"", \
989 *clear_field ? clear_escaped:"", \
990 *clear_field ? "'":"", \
992 *clear_field && *crypt_field ? ",":"", \
994 *crypt_field ? crypt_field:"", \
995 *crypt_field ? "='":"", \
996 *crypt_field ? crypt_escaped:"", \
997 *crypt_field ? "'":"", \
1000 has_domain || !*defdomain ? "":"@", \
1001 has_domain ? "":defdomain, \
1002 *where_clause ? " AND (":"", where_clause, \
1003 *where_clause ? ")":""
1006 sql_buf_size
=snprintf(dummy_buf
, 1, DEFAULT_SETPASS_UPDATE
);
1008 sql_buf
=malloc(sql_buf_size
+1);
1011 snprintf(sql_buf
, sql_buf_size
+1,
1012 DEFAULT_SETPASS_UPDATE
);
1014 free(username_escaped
);
1018 sql_buf
=parse_chpass_clause(chpass_clause
,
1025 free(clear_escaped
);
1026 free(crypt_escaped
);
1027 free(newpass_crypt
);
1029 if (courier_authdebug_login_level
>= 2)
1031 DPRINTF("setpass SQL: %s", sql_buf
);
1033 if (mysql_query (mysql
, sql_buf
))
1035 DPRINTF("setpass SQL failed");
1037 auth_mysql_cleanup();
1043 void auth_mysql_enumerate( void(*cb_func
)(const char *name
,
1046 const char *homedir
,
1047 const char *maildir
,
1048 const char *options
,
1052 const char *defdomain
, *select_clause
;
1057 if (do_connect()) return;
1061 select_clause
=read_env("MYSQL_ENUMERATE_CLAUSE");
1062 defdomain
=read_env("DEFAULT_DOMAIN");
1063 if (!defdomain
|| !defdomain
[0])
1064 defdomain
="*"; /* otherwise parse_select_clause fails */
1068 const char *user_table
,
1079 user_table
=read_env("MYSQL_USER_TABLE");
1083 err("authmysql: MYSQL_USER_TABLE not set in "
1088 uid_field
= read_env("MYSQL_UID_FIELD");
1089 if (!uid_field
) uid_field
= "uid";
1091 gid_field
= read_env("MYSQL_GID_FIELD");
1092 if (!gid_field
) gid_field
= "gid";
1094 login_field
= read_env("MYSQL_LOGIN_FIELD");
1095 if (!login_field
) login_field
= "id";
1097 home_field
= read_env("MYSQL_HOME_FIELD");
1098 if (!home_field
) home_field
= "home";
1100 maildir_field
=read_env("MYSQL_MAILDIR_FIELD");
1101 if (!maildir_field
) maildir_field
="\"\"";
1103 options_field
=read_env("MYSQL_AUXOPTIONS_FIELD");
1104 if (!options_field
) options_field
="\"\"";
1106 where_clause
=read_env("MYSQL_WHERE_CLAUSE");
1107 if (!where_clause
) where_clause
= "";
1110 #define DEFAULT_ENUMERATE_QUERY \
1111 "SELECT %s, %s, %s, %s, %s, %s FROM %s %s%s",\
1112 login_field, uid_field, gid_field, \
1113 home_field, maildir_field, \
1114 options_field, user_table, \
1115 *where_clause ? " WHERE ":"", \
1118 query_len
=snprintf(dummy_buf
, 1, DEFAULT_ENUMERATE_QUERY
);
1120 querybuf
=malloc(query_len
+1);
1128 snprintf(querybuf
, query_len
+1, DEFAULT_ENUMERATE_QUERY
);
1132 /* siefca@pld.org.pl */
1133 querybuf
=parse_select_clause (select_clause
, "*",
1134 defdomain
, "enumerate");
1137 DPRINTF("authmysql: parse_select_clause failed");
1141 DPRINTF("authmysql: enumerate query: %s", querybuf
);
1143 if (mysql_query (mysql
, querybuf
))
1145 DPRINTF("mysql_query failed, reconnecting: %s", mysql_error(mysql
));
1146 /* <o.blasnik@nextra.de> */
1148 auth_mysql_cleanup();
1156 if (mysql_query (mysql
, querybuf
))
1158 DPRINTF("mysql_query failed second time, giving up: %s", mysql_error(mysql
));
1160 auth_mysql_cleanup();
1166 result
= mysql_use_result (mysql
);
1169 const char *username
;
1172 const char *homedir
;
1173 const char *maildir
;
1174 const char *options
;
1176 while ((row
= mysql_fetch_row (result
)) != NULL
)
1178 if(!row
[0] || !row
[0][0]
1179 || !row
[1] || !row
[1][0]
1180 || !row
[2] || !row
[2][0]
1181 || !row
[3] || !row
[3][0])
1187 uid
=atol(row
[1]); /* FIXME use strtol to validate */
1193 if (maildir
&& !*maildir
)
1196 (*cb_func
)(username
, uid
, gid
, homedir
,
1197 maildir
, options
, void_arg
);
1200 /* NULL row could indicate end of result or an error */
1201 if (mysql_errno(mysql
))
1203 DPRINTF("mysql error during enumeration: %s", mysql_error(mysql
));
1206 (*cb_func
)(NULL
, 0, 0, NULL
, NULL
, NULL
, void_arg
);
1208 if (result
) mysql_free_result(result
);