/* GNU mailutils - a suite of utilities for electronic mail Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Library Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include struct myticket_data { char *user; char *pass; }; static char * stripwhite __P ((char *)); static int myticket_create __P ((ticket_t *, const char *, const char *)); static void myticket_destroy __P ((ticket_t)); static int _get_ticket __P ((ticket_t *, const char *, const char *)); static int myticket_pop __P ((ticket_t, const char *, char **)); static int _wicket_pop __P ((ticket_t, const char *, char **)); int wicket_create (wicket_t *pwicket, const char *filename) { ticket_t ticket; if (pwicket == NULL) return EINVAL; *pwicket = calloc (1, sizeof (**pwicket)); if (*pwicket == NULL) return ENOMEM; ticket = &(*pwicket)->ticket; if (filename) (*pwicket)->filename = strdup (filename); ticket_set_pop (ticket, _wicket_pop, NULL); ticket_set_data (ticket, *pwicket, NULL); return 0; } int wicket_to_ticket (wicket_t wicket, ticket_t * pticket) { if (wicket == NULL || pticket == NULL) return EINVAL; *pticket = &wicket->ticket; return 0; } int wicket_destroy (wicket_t * pwicket) { if (pwicket && *pwicket) { wicket_t wicket = *pwicket; if (wicket->filename) free (wicket->filename); free (wicket); *pwicket = NULL; } return 0; } int wicket_get_filename (wicket_t wicket, char *filename, size_t len, size_t *pwriten) { size_t n; if (wicket == NULL) return EINVAL; n = util_cpystr (filename, wicket->filename, len); if (pwriten) *pwriten = n; return 0; } int wicket_set_filename (wicket_t wicket, const char *filename) { if (wicket == NULL) return EINVAL; if (wicket->filename) free (wicket->filename); wicket->filename = (filename) ? strdup (filename) : NULL; return 0; } int wicket_set_ticket (wicket_t wicket, int _get_ticket __P ((wicket_t, const char *, const char *, ticket_t *))) { if (wicket == NULL) return EINVAL; wicket->_get_ticket = _get_ticket; return 0; } int wicket_get_ticket (wicket_t wicket, ticket_t *pticket, const char *user, const char *type) { if (wicket == NULL || pticket == NULL || user == NULL) return EINVAL; if (wicket->filename == NULL) return EINVAL; if (wicket->_get_ticket) return wicket->_get_ticket (wicket, user, type, pticket); return _get_ticket (pticket, wicket->filename, user); } /* FIXME: This is a proof of concept ... write a more intelligent parser. */ static int _get_ticket (ticket_t *pticket, const char *filename, const char *user) { FILE *fp; char *buf; size_t buflen; int status = ENOENT; fp = fopen (filename, "r"); if (fp == NULL) return errno; buflen = 128; buf = malloc (buflen); if (buf) { char *ptr = buf; while (fgets (ptr, buflen, fp) != NULL) { size_t len = strlen (buf); char *sep; /* Check if a complete line. */ if (len && buf[len - 1] != '\n') { char *tmp = realloc (buf, 2*buflen); if (tmp == NULL) { status = ENOMEM; break; } buf = tmp; ptr = buf + len; continue; } ptr = buf; /* Comments. */ if (*ptr == '#') continue; /* Skip leading spaces. */ while (isspace (*ptr)) { ptr++; len--; } /* user:passwd. Separator maybe ": \t" */ if (len && ((sep = memchr (ptr, ':', len)) != NULL || (sep = memchr (ptr, ' ', len)) != NULL || (sep = memchr (ptr, '\t', len)) != NULL)) { *sep++ = '\0'; ptr = stripwhite (ptr); if (strcmp (ptr, user) == 0) { sep = stripwhite (sep); status = myticket_create (pticket, ptr, sep); break; } } ptr = buf; } } else status = ENOMEM; if (buf) free (buf); fclose (fp); return status; } static int myticket_create (ticket_t *pticket, const char *user, const char *pass) { struct myticket_data *mdata; int status = ticket_create (pticket, NULL); if (status != 0) return status; mdata = calloc (1, sizeof *mdata); if (mdata == NULL) ticket_destroy (pticket, NULL); ticket_set_destroy (*pticket, myticket_destroy, NULL); ticket_set_pop (*pticket, myticket_pop, NULL); ticket_set_data (*pticket, mdata, NULL); if ((mdata->user = strdup (user)) == NULL || (mdata->pass = strdup (pass)) == NULL) { status = ENOMEM; ticket_destroy (pticket, NULL); } return status; } static int myticket_pop (ticket_t ticket, const char *challenge, char **parg) { struct myticket_data *mdata = NULL; ticket_get_data (ticket, (void **)&mdata); if (challenge && (strstr (challenge, "ass") != NULL || strstr (challenge, "ASS") != NULL)) *parg = strdup (mdata->pass); else *parg = strdup (mdata->user); return 0; } static int _wicket_pop (ticket_t ticket, const char *challenge, char **parg) { wicket_t wicket = NULL; ticket_t t = NULL; int status = 0; if ((status = ticket_get_data (ticket, (void **) &wicket)) != 0) return status; status = _get_ticket (&t, wicket->filename, NULL /* PROBLEM! Who do we want a ticket for? Can we crawl back to find the user? */ ); if (status == 0) status = myticket_pop (t, challenge, parg); if (t) ticket_destroy (&t, NULL); return status; } static void myticket_destroy (ticket_t ticket) { struct myticket_data *mdata = NULL; ticket_get_data (ticket, (void **)&mdata); if (mdata) { if (mdata->user) free (mdata->user); if (mdata->pass) free (mdata->pass); free (mdata); } } /* Strip whitespace from the start and end of STRING. Return a pointer into STRING. */ static char * stripwhite (char *string) { register char *s, *t; for (s = string; isspace (*s); s++) ; if (*s == 0) return (s); t = s + strlen (s) - 1; while (t > s && isspace (*t)) t--; *++t = '\0'; return s; }