/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2007, 2009, 2010 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int mu_wicket_create (mu_wicket_t *pwicket) { mu_wicket_t wicket = calloc (1, sizeof (*wicket)); if (!wicket) return ENOMEM; wicket->refcnt = 1; *pwicket = wicket; return 0; } int mu_wicket_get_ticket (mu_wicket_t wicket, const char *user, mu_ticket_t *pticket) { if (!wicket) return EINVAL; if (!pticket) return EINVAL; if (!wicket->_get_ticket) return ENOSYS; return wicket->_get_ticket (wicket, wicket->data, user, pticket); } int mu_wicket_ref (mu_wicket_t wicket) { if (!wicket) return EINVAL; wicket->refcnt++; return 0; } int mu_wicket_unref (mu_wicket_t wicket) { if (!wicket) return EINVAL; if (wicket->refcnt) wicket->refcnt--; if (wicket->refcnt == 0) { if (wicket->_destroy) wicket->_destroy (wicket); free (wicket); return 0; } return MU_ERR_EXISTS; } void mu_wicket_destroy (mu_wicket_t *pwicket) { if (pwicket && *pwicket && mu_wicket_unref (*pwicket) == 0) *pwicket = NULL; } int mu_wicket_set_destroy (mu_wicket_t wicket, void (*_destroy) (mu_wicket_t)) { if (!wicket) return EINVAL; wicket->_destroy = _destroy; return 0; } int mu_wicket_set_data (mu_wicket_t wicket, void *data) { if (!wicket) return EINVAL; wicket->data = data; return 0; } void * mu_wicket_get_data (mu_wicket_t wicket) { if (!wicket) return NULL; return wicket->data; } int mu_wicket_set_get_ticket (mu_wicket_t wicket, int (*_get_ticket) (mu_wicket_t, void *, const char *, mu_ticket_t *)) { if (!wicket) return EINVAL; wicket->_get_ticket = _get_ticket; return 0; } /* A "file wicket" implementation */ struct file_wicket { char *filename; }; static void _file_wicket_destroy (mu_wicket_t wicket) { struct file_wicket *fw = mu_wicket_get_data (wicket); free (fw->filename); free (fw); } struct file_ticket { char *filename; char *user; mu_url_t tickurl; }; static void file_ticket_destroy (mu_ticket_t ticket) { struct file_ticket *ft = mu_ticket_get_data (ticket); if (ft) { free (ft->filename); free (ft->user); mu_url_destroy (&ft->tickurl); free (ft); } } int file_ticket_get_cred (mu_ticket_t ticket, mu_url_t url, const char *challenge, char **pplain, mu_secret_t *psec) { struct file_ticket *ft = mu_ticket_get_data (ticket); if (!ft->tickurl) { int rc = mu_wicket_file_match_url (ft->filename, url, &ft->tickurl); if (rc) return rc; } if (pplain) { if (ft->user) { *pplain = strdup (ft->user); if (!*pplain) return ENOMEM; } else return mu_url_aget_user (ft->tickurl, pplain); } else return mu_url_get_secret (ft->tickurl, psec); } static int _file_wicket_get_ticket (mu_wicket_t wicket, void *data, const char *user, mu_ticket_t *pticket) { int rc; mu_ticket_t ticket; struct file_wicket *fw = data; struct file_ticket *ft = calloc (1, sizeof (*ft)); ft->filename = strdup (fw->filename); if (!ft->filename) { free (ft); return ENOMEM; } if (user) { ft->user = strdup (user); if (!ft->user) { free (ft->filename); free (ft); return ENOMEM; } } else ft->user = NULL; rc = mu_ticket_create (&ticket, NULL); if (rc) { free (ft->filename); free (ft->user); free (ft); return rc; } mu_ticket_set_destroy (ticket, file_ticket_destroy, NULL); mu_ticket_set_data (ticket, ft, NULL); mu_ticket_set_get_cred (ticket, file_ticket_get_cred, NULL); *pticket = ticket; return 0; } int mu_wicket_stream_match_url (mu_stream_t stream, struct mu_debug_locus *loc, mu_url_t url, mu_url_t *pticket_url) { int rc; mu_url_t u = NULL; char *buf = NULL; size_t bufsize = 0; size_t len; mu_url_t pret = NULL; int weight = 0; int line = loc->line; while ((rc = mu_stream_getline (stream, &buf, &bufsize, &len)) == 0 && len > 0) { char *p; int err; int n; loc->line++; p = mu_str_stripws (buf); /* Skip empty lines and comments. */ if (*p == 0 || *p == '#') continue; if ((err = mu_url_create (&u, p)) != 0) { /* Skip erroneous entry */ mu_error (_("%s:%u: cannot create URL: %s"), loc->file, loc->line, mu_strerror (err)); continue; } if ((err = mu_url_parse (u)) != 0) { mu_error (_("%s:%u: cannot parse URL: %s"), loc->file, loc->line, mu_strerror (err)); mu_url_destroy (&u); continue; } if (!mu_url_has_flag (u, MU_URL_USER|MU_URL_SECRET)) { mu_error (_("%s:%u: URL is missing required parts"), loc->file, loc->line); mu_url_destroy (&u); continue; } if (!mu_url_matches_ticket (u, url, &n)) { mu_url_destroy (&u); continue; } if (!pret || n < weight) { pret = u; weight = n; line = loc->line; if (weight == 0) break; } } free (buf); if (rc == 0) { if (pret) { *pticket_url = pret; loc->line = line; } else rc = MU_ERR_NOENT; } return rc; } int mu_wicket_file_match_url (const char *name, mu_url_t url, mu_url_t *pticket_url) { mu_stream_t stream; int rc; struct mu_debug_locus loc; rc = mu_file_stream_create (&stream, name, MU_STREAM_READ); if (rc) return rc; loc.file = name; loc.line = 0; rc = mu_wicket_stream_match_url (stream, &loc, url, pticket_url); mu_stream_close (stream); mu_stream_destroy (&stream); return rc; } int mu_file_wicket_create (mu_wicket_t *pwicket, const char *filename) { mu_wicket_t wicket; int rc; struct file_wicket *fw = calloc (1, sizeof (*fw)); if (!fw) return ENOMEM; fw->filename = strdup (filename); if (!fw->filename) { free (fw); return ENOMEM; } rc = mu_wicket_create (&wicket); if (rc) { free (fw->filename); free (fw); return rc; } mu_wicket_set_data (wicket, fw); mu_wicket_set_destroy (wicket, _file_wicket_destroy); mu_wicket_set_get_ticket (wicket, _file_wicket_get_ticket); *pwicket = wicket; return 0; }