Commit c15e8df9 c15e8df9e63d618a49c627055762c482aafad0ea by Sergey Poznyakoff

Implement field mapping and retrieval by field names

1 parent 2ab1e3f5
Showing 1 changed file with 174 additions and 12 deletions
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. 2 Copyright (C) 2002, 2003, 2004, 2005, 2006,
3 2007 Free Software Foundation, Inc.
3 4
4 This library is free software; you can redistribute it and/or 5 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public 6 modify it under the terms of the GNU Lesser General Public
...@@ -39,6 +40,7 @@ ...@@ -39,6 +40,7 @@
39 # include <crypt.h> 40 # include <crypt.h>
40 #endif 41 #endif
41 42
43 #include <mailutils/assoc.h>
42 #include <mailutils/list.h> 44 #include <mailutils/list.h>
43 #include <mailutils/iterator.h> 45 #include <mailutils/iterator.h>
44 #include <mailutils/mailbox.h> 46 #include <mailutils/mailbox.h>
...@@ -47,6 +49,7 @@ ...@@ -47,6 +49,7 @@
47 #include <mailutils/error.h> 49 #include <mailutils/error.h>
48 #include <mailutils/errno.h> 50 #include <mailutils/errno.h>
49 #include <mailutils/nls.h> 51 #include <mailutils/nls.h>
52 #include <mailutils/mutil.h>
50 #include <mailutils/sql.h> 53 #include <mailutils/sql.h>
51 54
52 #ifdef USE_SQL 55 #ifdef USE_SQL
...@@ -66,6 +69,8 @@ int mu_sql_port = 0; /* Port number to connect to. ...@@ -66,6 +69,8 @@ int mu_sql_port = 0; /* Port number to connect to.
66 0 means default port */ 69 0 means default port */
67 enum mu_password_type mu_sql_password_type = password_hash; 70 enum mu_password_type mu_sql_password_type = password_hash;
68 71
72 static mu_assoc_t sql_field_map;
73
69 static char * 74 static char *
70 sql_escape_string (const char *ustr) 75 sql_escape_string (const char *ustr)
71 { 76 {
...@@ -170,16 +175,17 @@ mu_sql_expand_query (const char *query, const char *ustr) ...@@ -170,16 +175,17 @@ mu_sql_expand_query (const char *query, const char *ustr)
170 return res; 175 return res;
171 } 176 }
172 177
173 # define ARG_SQL_INTERFACE 256 178 # define ARG_SQL_INTERFACE 256
174 # define ARG_SQL_GETPWNAM 257 179 # define ARG_SQL_GETPWNAM 257
175 # define ARG_SQL_GETPWUID 258 180 # define ARG_SQL_GETPWUID 258
176 # define ARG_SQL_GETPASS 259 181 # define ARG_SQL_GETPASS 259
177 # define ARG_SQL_HOST 260 182 # define ARG_SQL_HOST 260
178 # define ARG_SQL_USER 261 183 # define ARG_SQL_USER 261
179 # define ARG_SQL_PASSWD 262 184 # define ARG_SQL_PASSWD 262
180 # define ARG_SQL_DB 263 185 # define ARG_SQL_DB 263
181 # define ARG_SQL_PORT 264 186 # define ARG_SQL_PORT 264
182 # define ARG_SQL_MU_PASSWORD_TYPE 265 187 # define ARG_SQL_MU_PASSWORD_TYPE 265
188 # define ARG_SQL_FIELD_MAP 266
183 189
184 static struct argp_option mu_sql_argp_option[] = { 190 static struct argp_option mu_sql_argp_option[] = {
185 {"sql-interface", ARG_SQL_INTERFACE, N_("NAME"), 0, 191 {"sql-interface", ARG_SQL_INTERFACE, N_("NAME"), 0,
...@@ -202,12 +208,17 @@ static struct argp_option mu_sql_argp_option[] = { ...@@ -202,12 +208,17 @@ static struct argp_option mu_sql_argp_option[] = {
202 N_("Port to use"), 0}, 208 N_("Port to use"), 0},
203 {"sql-password-type", ARG_SQL_MU_PASSWORD_TYPE, N_("STRING"), 0, 209 {"sql-password-type", ARG_SQL_MU_PASSWORD_TYPE, N_("STRING"), 0,
204 N_("Type of password returned by --sql-getpass query. STRING is one of: plain, hash, scrambled"), 0}, 210 N_("Type of password returned by --sql-getpass query. STRING is one of: plain, hash, scrambled"), 0},
211 {"sql-field-map", ARG_SQL_FIELD_MAP, N_("MAP"), 0,
212 N_("Declare a name translation map for SQL fields in results of sql-getpwnam and "
213 "sql-getpwuid queries"), 0},
205 { NULL, 0, NULL, 0, NULL, 0 } 214 { NULL, 0, NULL, 0, NULL, 0 }
206 }; 215 };
207 216
208 static error_t 217 static error_t
209 mu_sql_argp_parser (int key, char *arg, struct argp_state *state) 218 mu_sql_argp_parser (int key, char *arg, struct argp_state *state)
210 { 219 {
220 int rc, err;
221
211 switch (key) 222 switch (key)
212 { 223 {
213 case ARG_SQL_INTERFACE: 224 case ARG_SQL_INTERFACE:
...@@ -258,6 +269,13 @@ mu_sql_argp_parser (int key, char *arg, struct argp_state *state) ...@@ -258,6 +269,13 @@ mu_sql_argp_parser (int key, char *arg, struct argp_state *state)
258 else 269 else
259 argp_error (state, _("Unknown password type `%s'"), arg); 270 argp_error (state, _("Unknown password type `%s'"), arg);
260 break; 271 break;
272
273 case ARG_SQL_FIELD_MAP:
274 rc = mutil_parse_field_map (arg, &sql_field_map, &err);
275 if (rc)
276 argp_error (state, _("Error near element %d: %s"),
277 err, mu_strerror (rc));
278 break;
261 279
262 default: 280 default:
263 return ARGP_ERR_UNKNOWN; 281 return ARGP_ERR_UNKNOWN;
...@@ -271,7 +289,8 @@ struct argp mu_sql_argp = { ...@@ -271,7 +289,8 @@ struct argp mu_sql_argp = {
271 }; 289 };
272 290
273 static int 291 static int
274 decode_tuple (mu_sql_connection_t conn, int n, struct mu_auth_data **return_data) 292 decode_tuple_v1_0 (mu_sql_connection_t conn, int n,
293 struct mu_auth_data **return_data)
275 { 294 {
276 int rc; 295 int rc;
277 char *mailbox_name = NULL; 296 char *mailbox_name = NULL;
...@@ -296,10 +315,15 @@ decode_tuple (mu_sql_connection_t conn, int n, struct mu_auth_data **return_data ...@@ -296,10 +315,15 @@ decode_tuple (mu_sql_connection_t conn, int n, struct mu_auth_data **return_data
296 char *passwd, *suid, *sgid, *dir, *shell; 315 char *passwd, *suid, *sgid, *dir, *shell;
297 316
298 if (mu_sql_get_column (conn, 0, 1, &passwd) 317 if (mu_sql_get_column (conn, 0, 1, &passwd)
318 || !passwd
299 || mu_sql_get_column (conn, 0, 2, &suid) 319 || mu_sql_get_column (conn, 0, 2, &suid)
320 || !suid
300 || mu_sql_get_column (conn, 0, 3, &sgid) 321 || mu_sql_get_column (conn, 0, 3, &sgid)
322 || !sgid
301 || mu_sql_get_column (conn, 0, 4, &dir) 323 || mu_sql_get_column (conn, 0, 4, &dir)
302 || mu_sql_get_column (conn, 0, 5, &shell)) 324 || !dir
325 || mu_sql_get_column (conn, 0, 5, &shell)
326 || !shell)
303 return MU_ERR_FAILURE; 327 return MU_ERR_FAILURE;
304 328
305 rc = mu_auth_data_alloc (return_data, 329 rc = mu_auth_data_alloc (return_data,
...@@ -321,6 +345,144 @@ decode_tuple (mu_sql_connection_t conn, int n, struct mu_auth_data **return_data ...@@ -321,6 +345,144 @@ decode_tuple (mu_sql_connection_t conn, int n, struct mu_auth_data **return_data
321 } 345 }
322 346
323 static int 347 static int
348 get_field (mu_sql_connection_t conn, const char *id, char **ret, int mandatory)
349 {
350 const char **name = mu_assoc_ref (sql_field_map, id);
351 int rc = mu_sql_get_field (conn, 0, name ? *name : id, ret);
352 if (rc)
353 {
354 if (mandatory || rc != MU_ERR_NOENT)
355 mu_error (_("Cannot get SQL field `%s' (`%s'): %s"),
356 id, name ? *name : id, mu_strerror (rc));
357 }
358 else if (!*ret)
359 {
360 mu_error (_("SQL field `%s' (`%s') has NULL value"),
361 id, name ? *name : id);
362 rc = MU_READ_ERROR;
363 }
364
365 return rc;
366 }
367
368 static int
369 decode_tuple_new (mu_sql_connection_t conn, int n,
370 struct mu_auth_data **return_data)
371 {
372 int rc;
373 char *mailbox_name = NULL;
374 char *name;
375 char *passwd, *suid, *sgid, *dir, *shell, *gecos, *squota;
376 mu_off_t quota = 0;
377 char *p;
378 uid_t uid;
379 gid_t gid;
380
381 if (get_field (conn, MU_AUTH_NAME, &name, 1)
382 || get_field (conn, MU_AUTH_PASSWD, &passwd, 1)
383 || get_field (conn, MU_AUTH_UID, &suid, 1)
384 || get_field (conn, MU_AUTH_GID, &sgid, 1)
385 || get_field (conn, MU_AUTH_DIR, &dir, 1)
386 || get_field (conn, MU_AUTH_SHELL, &shell, 1))
387 return MU_ERR_FAILURE;
388
389 if (get_field (conn, MU_AUTH_GECOS, &gecos, 0))
390 gecos = "SQL user";
391
392 uid = strtoul (suid, &p, 0);
393 if (*p)
394 {
395 mu_error (_("Invalid value for uid: %s"), suid);
396 return MU_ERR_FAILURE;
397 }
398
399 gid = strtoul (sgid, &p, 0);
400 if (*p)
401 {
402 mu_error (_("Invalid value for gid: %s"), sgid);
403 return MU_ERR_FAILURE;
404 }
405
406 rc = get_field (conn, MU_AUTH_MAILBOX, &mailbox_name, 0);
407 switch (rc)
408 {
409 case 0:
410 mailbox_name = strdup (mailbox_name);
411 break;
412
413 case MU_ERR_NOENT:
414 if (mu_construct_user_mailbox_url (&mailbox_name, name))
415 return MU_ERR_FAILURE;
416 break;
417
418 default:
419 return MU_ERR_FAILURE;
420 }
421
422 rc = get_field (conn, MU_AUTH_QUOTA, &squota, 0);
423 if (rc == 0)
424 {
425 if (strcasecmp (squota, "none") == 0)
426 quota = 0;
427 else
428 {
429 quota = strtoul (squota, &p, 10);
430 switch (*p)
431 {
432 case 0:
433 break;
434
435 case 'k':
436 case 'K':
437 quota *= 1024;
438 break;
439
440 case 'm':
441 case 'M':
442 quota *= 1024*1024;
443 break;
444
445 default:
446 mu_error (_("Invalid value for quota: %s"), squota);
447 free (mailbox_name);
448 return MU_ERR_FAILURE;
449 }
450 }
451 }
452 else if (rc == MU_ERR_NOENT)
453 quota = 0;
454 else
455 {
456 free (mailbox_name);
457 return MU_ERR_FAILURE;
458 }
459
460 rc = mu_auth_data_alloc (return_data,
461 name,
462 passwd,
463 uid,
464 gid,
465 gecos,
466 dir,
467 shell,
468 mailbox_name,
469 1);
470
471 free (mailbox_name);
472 return rc;
473 }
474
475 static int
476 decode_tuple (mu_sql_connection_t conn, int n,
477 struct mu_auth_data **return_data)
478 {
479 if (sql_field_map)
480 return decode_tuple_new (conn, n, return_data);
481 else
482 return decode_tuple_v1_0 (conn, n, return_data);
483 }
484
485 static int
324 mu_auth_sql_by_name (struct mu_auth_data **return_data, 486 mu_auth_sql_by_name (struct mu_auth_data **return_data,
325 const void *key, 487 const void *key,
326 void *func_data ARG_UNUSED, 488 void *func_data ARG_UNUSED,
......