Page MenuHomePhorge

pop3d.c
No OneTemporary

Authored By
Unknown
Size
23 KB
Referenced Files
None
Subscribers
None
/* pop3d.c -- POP3 server protocol parsing
*
* (C) Copyright 1994 by Carnegie Mellon University
*
* All Rights Reserved
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Carnegie
* Mellon University not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. Carnegie Mellon University makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/param.h>
#include <syslog.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "acl.h"
#include "util.h"
#include "auth.h"
#include "acte.h"
#include "config.h"
#include "prot.h"
#include "sysexits.h"
#include "imap_err.h"
#include "mailbox.h"
#include "version.h"
#include "xmalloc.h"
extern int optind;
extern char *optarg;
extern int opterr;
extern int errno;
#ifdef HAVE_ACTE_KRB
#include <krb.h>
/* MIT's kpop authentication kludge */
int kflag = 0;
char klrealm[REALM_SZ];
AUTH_DAT kdata;
#endif
char *popd_userid = 0;
struct mailbox *popd_mailbox = 0;
struct sockaddr_in popd_localaddr, popd_remoteaddr;
int popd_haveaddr = 0;
char popd_clienthost[250] = "[local]";
struct protstream *popd_out, *popd_in;
unsigned popd_exists = 0;
unsigned popd_highest;
unsigned popd_login_time;
struct msg {
unsigned uid;
unsigned size;
int deleted;
} *popd_msg;
static struct mailbox mboxstruct;
static int expungedeleted();
main(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
int opt;
char hostname[MAXHOSTNAMELEN+1];
int salen;
struct hostent *hp;
struct sockaddr_in sa;
int timeout;
popd_in = prot_new(0, 0);
popd_out = prot_new(1, 1);
if (geteuid() == 0) fatal("must run as the Cyrus user", EX_USAGE);
opterr = 0;
while ((opt = getopt(argc, argv, "k")) != EOF) {
switch(opt) {
#ifdef HAVE_ACTE_KRB
case 'k':
kflag++;
break;
#endif
default:
usage();
}
}
setproctitle_init(argc, argv, envp);
config_init("pop3d");
signal(SIGPIPE, SIG_IGN);
gethostname(hostname, sizeof(hostname));
/* Find out name of client host */
salen = sizeof(popd_remoteaddr);
if (getpeername(0, (struct sockaddr *)&popd_remoteaddr, &salen) == 0 &&
popd_remoteaddr.sin_family == AF_INET) {
if (hp = gethostbyaddr((char *)&popd_remoteaddr.sin_addr,
sizeof(popd_remoteaddr.sin_addr), AF_INET)) {
if (strlen(hp->h_name) + 30 > sizeof(popd_clienthost)) {
hp->h_name[sizeof(popd_clienthost)-30] = '\0';
}
strcpy(popd_clienthost, hp->h_name);
}
else {
popd_clienthost[0] = '\0';
}
strcat(popd_clienthost, "[");
strcat(popd_clienthost, inet_ntoa(popd_remoteaddr.sin_addr));
strcat(popd_clienthost, "]");
salen = sizeof(popd_localaddr);
if (getsockname(0, (struct sockaddr *)&popd_localaddr, &salen) == 0) {
popd_haveaddr = 1;
}
}
proc_register("pop3d", popd_clienthost, (char *)0, (char *)0);
/* Set inactivity timer */
timeout = config_getint("poptimeout", 10);
if (timeout < 10) timeout = 10;
prot_settimeout(popd_in, timeout*60);
#ifdef HAVE_ACTE_KRB
if (kflag) kpop();
#endif
prot_printf(popd_out,"+OK %s Cyrus POP3 %s server ready\r\n",
hostname, CYRUS_VERSION);
cmdloop();
}
usage()
{
prot_printf(popd_out, "-ERR usage: pop3d%s\r\n",
#ifdef HAVE_ACTE_KRB
" [-k]"
#else
""
#endif
);
prot_flush(popd_out);
exit(EX_USAGE);
}
/*
* Cleanly shut down and exit
*/
shut_down(code)
int code;
{
proc_cleanup();
if (popd_mailbox) {
mailbox_close(popd_mailbox);
}
prot_flush(popd_out);
exit(code);
}
fatal(s, code)
char *s;
int code;
{
static int recurse_code = 0;
if (recurse_code) {
/* We were called recursively. Just give up */
proc_cleanup();
exit(recurse_code);
}
recurse_code = code;
prot_printf(popd_out, "-ERR Fatal error: %s\r\n", s);
prot_flush(popd_out);
shut_down(code);
}
#ifdef HAVE_ACTE_KRB
/*
* MIT's kludge of a kpop protocol
* Client does a krb_sendauth() first thing
*/
kpop()
{
Key_schedule schedule;
KTEXT_ST ticket;
char instance[INST_SZ];
char version[9];
const char *srvtab;
int r;
if (!popd_haveaddr) {
fatal("Cannot get client's IP address");
}
srvtab = config_getstring("srvtab", "");
strcpy(instance, "*");
r = krb_recvauth(0L, 0, &ticket, "pop", instance,
&popd_remoteaddr, (struct sockaddr_in *) NULL,
&kdata, srvtab, schedule, version);
if (r) {
prot_printf(popd_out, "-ERR Kerberos authentication failure: %s\r\n",
krb_err_txt[r]);
syslog(LOG_NOTICE,
"badlogin: %s kpop ? %s%s%s@%s %s",
popd_clienthost, kdata.pname,
kdata.pinst[0] ? "." : "", kdata.pinst,
kdata.prealm, krb_err_txt[r]);
shut_down(0);
}
r = krb_get_lrealm(klrealm,1);
if (r) {
prot_printf(popd_out, "-ERR Kerberos failure: %s\r\n",
krb_err_txt[r]);
syslog(LOG_NOTICE,
"badlogin: %s kpop ? %s%s%s@%s krb_get_lrealm: %s",
popd_clienthost, kdata.pname,
kdata.pinst[0] ? "." : "", kdata.pinst,
kdata.prealm, krb_err_txt[r]);
shut_down(0);
}
}
#endif
/*
* Top-level command loop parsing
*/
cmdloop()
{
char inputbuf[8192];
char *p, *arg;
unsigned msg;
for (;;) {
prot_flush(popd_out);
if (!prot_fgets(inputbuf, sizeof(inputbuf), popd_in)) {
shut_down(0);
}
p = inputbuf + strlen(inputbuf);
if (p > inputbuf && p[-1] == '\n') *--p = '\0';
if (p > inputbuf && p[-1] == '\r') *--p = '\0';
/* Parse into keword and argument */
for (p = inputbuf; *p && !isspace(*p); p++);
if (*p) {
*p++ = '\0';
for (arg=p; *arg && isspace(*arg); arg++);
if (!*arg) {
prot_printf(popd_out, "-ERR Syntax error\r\n");
continue;
}
}
else {
arg = 0;
}
lcase(inputbuf);
if (!strcmp(inputbuf, "quit")) {
if (!arg) {
if (popd_mailbox) {
if (!mailbox_lock_index(popd_mailbox)) {
popd_mailbox->pop3_last_login = popd_login_time;
mailbox_write_index_header(popd_mailbox);
mailbox_unlock_index(popd_mailbox);
}
for (msg = 1; msg <= popd_exists; msg++) {
if (popd_msg[msg].deleted) break;
}
if (msg <= popd_exists) {
(void) mailbox_expunge(popd_mailbox, 1, expungedeleted, 0);
}
}
printf("+OK\r\n");
shut_down(0);
}
else prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
if (!popd_mailbox) {
if (!strcmp(inputbuf, "user")) {
if (popd_userid) {
prot_printf(popd_out, "-ERR Must give PASS command\r\n");
}
else if (!arg) {
prot_printf(popd_out, "-ERR Missing argument\r\n");
}
else if (!(p = auth_canonifyid(arg)) ||
strchr(p, '.') || strlen(p) + 6 > MAX_MAILBOX_PATH) {
prot_printf(popd_out, "-ERR Invalid user\r\n");
syslog(LOG_NOTICE,
"badlogin: %s plaintext %s invalid user",
popd_clienthost, beautify_string(arg));
}
else {
popd_userid = xstrdup(p);
prot_printf(popd_out, "+OK Name is a valid mailbox\r\n");
}
}
else if (!strcmp(inputbuf, "pass")) {
if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
else cmd_pass(arg);
}
else if (!strcmp(inputbuf, "auth")) {
if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
else cmd_auth(arg);
}
else {
prot_printf(popd_out, "-ERR Unrecognized command\r\n");
}
}
else if (!strcmp(inputbuf, "stat")) {
unsigned nmsgs = 0, totsize = 0;
if (arg) {
prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
else {
for (msg = 1; msg <= popd_exists; msg++) {
if (!popd_msg[msg].deleted) {
nmsgs++;
totsize += popd_msg[msg].size;
}
}
prot_printf(popd_out, "+OK %u %u\r\n", nmsgs, totsize);
}
}
else if (!strcmp(inputbuf, "list")) {
if (arg) {
msg = parsenum(&arg);
if (arg) {
prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
else if (msg < 1 || msg > popd_exists ||
popd_msg[msg].deleted) {
prot_printf(popd_out, "-ERR No such message\r\n");
}
else {
prot_printf(popd_out, "+OK %u %u\r\n", msg, popd_msg[msg].size);
}
}
else {
prot_printf(popd_out, "+OK scan listing follows\r\n");
for (msg = 1; msg <= popd_exists; msg++) {
if (!popd_msg[msg].deleted) {
prot_printf(popd_out, "%u %u\r\n", msg, popd_msg[msg].size);
}
}
prot_printf(popd_out, ".\r\n");
}
}
else if (!strcmp(inputbuf, "retr")) {
if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
else {
msg = parsenum(&arg);
if (arg) {
prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
else if (msg < 1 || msg > popd_exists ||
popd_msg[msg].deleted) {
prot_printf(popd_out, "-ERR No such message\r\n");
}
else {
if (msg > popd_highest) popd_highest = msg;
blat(msg, -1);
}
}
}
else if (!strcmp(inputbuf, "dele")) {
if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
else {
msg = parsenum(&arg);
if (arg) {
prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
else if (msg < 1 || msg > popd_exists ||
popd_msg[msg].deleted) {
prot_printf(popd_out, "-ERR No such message\r\n");
}
else {
popd_msg[msg].deleted = 1;
if (msg > popd_highest) popd_highest = msg;
prot_printf(popd_out, "+OK message deleted\r\n");
}
}
}
else if (!strcmp(inputbuf, "noop")) {
if (arg) {
prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
else {
prot_printf(popd_out, "+OK\r\n");
}
}
else if (!strcmp(inputbuf, "last")) {
if (arg) {
prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
else {
prot_printf(popd_out, "+OK %u\r\n", popd_highest);
}
}
else if (!strcmp(inputbuf, "rset")) {
if (arg) {
prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
else {
popd_highest = 0;
for (msg = 1; msg <= popd_exists; msg++) {
popd_msg[msg].deleted = 0;
}
prot_printf(popd_out, "+OK\r\n");
}
}
else if (!strcmp(inputbuf, "top")) {
int lines;
if (arg) msg = parsenum(&arg);
if (!arg) prot_printf(popd_out, "-ERR Missing argument\r\n");
else {
lines = parsenum(&arg);
if (arg) {
prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
else if (msg < 1 || msg > popd_exists ||
popd_msg[msg].deleted) {
prot_printf(popd_out, "-ERR No such message\r\n");
}
else if (lines < 0) {
prot_printf(popd_out, "-ERR Invalid number of lines\r\n");
}
else {
blat(msg, lines);
}
}
}
else if (!strcmp(inputbuf, "uidl")) {
if (arg) {
msg = parsenum(&arg);
if (arg) {
prot_printf(popd_out, "-ERR Unexpected extra argument\r\n");
}
else if (msg < 1 || msg > popd_exists ||
popd_msg[msg].deleted) {
prot_printf(popd_out, "-ERR No such message\r\n");
}
else {
prot_printf(popd_out, "+OK %u %u\r\n", msg, popd_msg[msg].uid);
}
}
else {
prot_printf(popd_out, "+OK unique-id listing follows\r\n");
for (msg = 1; msg <= popd_exists; msg++) {
if (!popd_msg[msg].deleted) {
prot_printf(popd_out, "%u %u\r\n", msg, popd_msg[msg].uid);
}
}
prot_printf(popd_out, ".\r\n");
}
}
else {
prot_printf(popd_out, "-ERR Unrecognized command\r\n");
}
}
}
cmd_pass(pass)
char *pass;
{
char *reply = 0;
int plaintextloginpause;
if (!popd_userid) {
prot_printf(popd_out, "-ERR Must give USER command\r\n");
return;
}
#ifdef HAVE_ACTE_KRB
if (kflag) {
if (strcmp(popd_userid, kdata.pname) != 0 ||
kdata.pinst[0] ||
strcmp(klrealm, kdata.prealm) != 0) {
prot_printf(popd_out, "-ERR Invalid login\r\n");
syslog(LOG_NOTICE,
"badlogin: %s kpop %s %s%s%s@%s access denied",
popd_clienthost, popd_userid,
kdata.pname, kdata.pinst[0] ? "." : "",
kdata.pinst, kdata.prealm);
return;
}
syslog(LOG_NOTICE, "login: %s %s kpop", popd_clienthost, popd_userid);
openinbox();
return;
}
#endif
if (!strcmp(popd_userid, "anonymous")) {
if (config_getswitch("allowanonymouslogin", 0)) {
pass = beautify_string(pass);
if (strlen(pass) > 500) pass[500] = '\0';
syslog(LOG_NOTICE, "login: %s anonymous %s",
popd_clienthost, pass);
}
else {
syslog(LOG_NOTICE, "badlogin: %s anonymous login refused",
popd_clienthost);
prot_printf(popd_out, "-ERR Invalid login\r\n");
return;
}
}
else if (login_plaintext(popd_userid, pass, &reply) != 0) {
if (reply) {
syslog(LOG_NOTICE, "badlogin: %s plaintext %s %s",
popd_clienthost, popd_userid, reply);
}
free(popd_userid);
popd_userid = 0;
sleep(3);
prot_printf(popd_out, "-ERR Invalid login\r\n");
return;
}
else {
syslog(LOG_NOTICE, "login: %s %s plaintext %s",
popd_clienthost, popd_userid, reply ? reply : "");
if (plaintextloginpause = config_getint("plaintextloginpause", 0)) {
sleep(plaintextloginpause);
}
}
openinbox();
}
cmd_auth(authtype)
char *authtype;
{
char *canon_user;
int r;
struct acte_server *mech;
int (*authproc)();
int outputlen;
char *output;
int inputlen;
char *input;
void *state;
const char *reply = 0;
int protlevel;
char *user;
acte_encodefunc_t *encodefunc;
acte_decodefunc_t *decodefunc;
int maxplain;
char *val;
lcase(authtype);
r = login_authenticate(authtype, &mech, &authproc, &reply);
if (!r) {
r = mech->start("pop", authproc, ACTE_PROT_ANY, PROT_BUFSIZE,
popd_haveaddr ? (struct sockaddr *)&popd_localaddr : 0,
popd_haveaddr ? (struct sockaddr *)&popd_remoteaddr : 0,
&outputlen, &output, &state, &reply);
}
if (r && r != ACTE_DONE) {
if (reply) {
syslog(LOG_NOTICE, "badlogin: %s %s %s",
popd_clienthost, authtype, reply);
}
prot_printf(popd_out, "-ERR Invalid login\r\n");
return;
}
while (r == 0) {
printauthready(outputlen, output);
inputlen = readbase64string(&input);
if (inputlen == -1) {
prot_printf(popd_out, "-ERR Invalid base64 string\r\n");
mech->free_state(state);
return;
}
r = mech->auth(state, inputlen, input, &outputlen, &output, &reply);
}
if (r != ACTE_DONE) {
mech->free_state(state);
if (reply) {
syslog(LOG_NOTICE, "badlogin: %s %s %s",
popd_clienthost, authtype, reply);
}
sleep(3);
prot_printf(popd_out, "-ERR Invalid login\r\n");
return;
}
mech->query_state(state, &user, &protlevel, &encodefunc, &decodefunc,
&maxplain);
canon_user = auth_canonifyid(user);
if (!canon_user || strchr(canon_user, '.') ||
strlen(canon_user) + 6 > MAX_MAILBOX_PATH) {
syslog(LOG_NOTICE, "badlogin: %s %s %s bad userid",
popd_clienthost, authtype, beautify_string(user));
mech->free_state(state);
prot_printf(popd_out, "-ERR Invalid user\r\n");
return;
}
popd_userid = xstrdup(canon_user);
syslog(LOG_NOTICE, "login: %s %s %s %s", popd_clienthost, canon_user,
authtype, reply ? reply : "");
if (openinbox() == 0 && (encodefunc || decodefunc)) {
prot_setfunc(popd_in, decodefunc, state, 0);
prot_setfunc(popd_out, encodefunc, state, maxplain);
}
else {
mech->free_state(state);
}
}
/*
* Complete the login process by opening and locking the user's inbox
*/
int openinbox()
{
char inboxname[MAX_MAILBOX_PATH];
int r, msg;
struct index_record record;
char buf[MAX_MAILBOX_PATH];
FILE *logfile;
int minpoll;
popd_login_time = time(0);
strcpy(inboxname, "user.");
strcat(inboxname, popd_userid);
r = mailbox_open_header(inboxname, 0, &mboxstruct);
if (r) {
free(popd_userid);
popd_userid = 0;
sleep(3);
prot_printf(popd_out, "-ERR Invalid login\r\n");
return 1;
}
r = mailbox_open_index(&mboxstruct);
if (!r) r = mailbox_lock_pop(&mboxstruct);
if (r) {
mailbox_close(&mboxstruct);
free(popd_userid);
popd_userid = 0;
prot_printf(popd_out, "-ERR Unable to lock maildrop\r\n");
return 1;
}
if ((minpoll = config_getint("popminpoll", 0)) &&
mboxstruct.pop3_last_login + 60*minpoll > popd_login_time) {
prot_printf(popd_out,
"-ERR Logins must be at least %d minute%s apart\r\n",
minpoll, minpoll > 1 ? "s" : "");
if (!mailbox_lock_index(&mboxstruct)) {
mboxstruct.pop3_last_login = popd_login_time;
mailbox_write_index_header(&mboxstruct);
}
mailbox_close(&mboxstruct);
free(popd_userid);
popd_userid = 0;
return 1;
}
if (chdir(mboxstruct.path)) {
syslog(LOG_ERR, "IOERROR: changing directory to %s: %m",
mboxstruct.path);
r = IMAP_IOERROR;
}
if (!r) {
popd_exists = mboxstruct.exists;
popd_highest = 0;
popd_msg = (struct msg *)xmalloc((popd_exists+1) * sizeof(struct msg));
for (msg = 1; msg <= popd_exists; msg++) {
if (r = mailbox_read_index_record(&mboxstruct, msg, &record))
break;
popd_msg[msg].uid = record.uid;
popd_msg[msg].size = record.size;
popd_msg[msg].deleted = 0;
}
}
if (r) {
mailbox_close(&mboxstruct);
free(popd_userid);
popd_userid = 0;
free(popd_msg);
popd_msg = 0;
popd_exists = 0;
prot_printf(popd_out, "-ERR Unable to read maildrop\r\n");
return 1;
}
popd_mailbox = &mboxstruct;
proc_register("pop3d", popd_clienthost, popd_userid, popd_mailbox->name);
/* Create telemetry log */
sprintf(buf, "%s%s%s/%u", config_dir, FNAME_LOGDIR, popd_userid,
getpid());
logfile = fopen(buf, "w");
if (logfile) {
prot_setlog(popd_in, fileno(logfile));
prot_setlog(popd_out, fileno(logfile));
}
prot_printf(popd_out, "+OK Maildrop locked and ready\r\n");
return 0;
}
blat(msg, lines)
int msg;
int lines;
{
FILE *msgfile;
char buf[4096];
int thisline = -2;
msgfile = fopen(mailbox_message_fname(popd_mailbox, popd_msg[msg].uid),
"r");
if (!msgfile) {
prot_printf(popd_out, "-ERR Could not read message file\r\n");
return;
}
prot_printf(popd_out, "+OK Message follows\r\n");
while (lines != thisline) {
if (!fgets(buf, sizeof(buf), msgfile)) break;
if (thisline < 0) {
if (buf[0] == '\r' && buf[1] == '\n') thisline = 0;
}
else thisline++;
if (buf[0] == '.') prot_putc('.', popd_out);
do {
prot_printf(popd_out, "%s", buf);
}
while (buf[strlen(buf)-1] != '\n' && fgets(buf, sizeof(buf), msgfile));
}
fclose(msgfile);
prot_printf(popd_out, ".\r\n");
}
int parsenum(ptr)
char **ptr;
{
char *p = *ptr;
int result = 0;
if (!isdigit(*p)) {
*ptr = 0;
return -1;
}
while (*p && isdigit(*p)) {
result = result * 10 + *p++ - '0';
}
if (*p) {
while (*p && isspace(*p)) p++;
*ptr = p;
}
else *ptr = 0;
return result;
}
static int expungedeleted(rock, index)
char *rock;
char *index;
{
int msg;
int uid = ntohl(*((bit32 *)(index+OFFSET_UID)));
for (msg = 1; msg <= popd_exists; msg++) {
if (popd_msg[msg].uid == uid) {
return popd_msg[msg].deleted;
}
}
return 0;
}
/*
* Print an authentication ready response
*/
static char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
printauthready(len, data)
int len;
unsigned char *data;
{
int c1, c2, c3;
prot_putc('+', popd_out);
prot_putc(' ', popd_out);
while (len) {
c1 = *data++;
len--;
prot_putc(basis_64[c1>>2], popd_out);
if (len == 0) c2 = 0;
else c2 = *data++;
prot_putc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], popd_out);
if (len == 0) {
prot_putc('=', popd_out);
prot_putc('=', popd_out);
break;
}
if (--len == 0) c3 = 0;
else c3 = *data++;
prot_putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], popd_out);
if (len == 0) {
prot_putc('=', popd_out);
break;
}
--len;
prot_putc(basis_64[c3 & 0x3F], popd_out);
}
prot_putc('\r', popd_out);
prot_putc('\n', popd_out);
prot_flush(popd_out);
}
#define XX 127
/*
* Table for decoding base64
*/
static const char index_64[256] = {
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,XX,XX,XX,
XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
};
#define CHAR64(c) (index_64[(unsigned char)(c)])
#define BUFGROWSIZE 100
/*
* Parse a base64_string
*/
int readbase64string(ptr)
char **ptr;
{
int c1, c2, c3, c4;
int i, len = 0;
static char *buf;
static int alloc = 0;
if (alloc == 0) {
alloc = BUFGROWSIZE;
buf = xmalloc(alloc+1);
}
for (;;) {
c1 = prot_getc(popd_in);
if (c1 == '\r') {
c1 = prot_getc(popd_in);
if (c1 != '\n') {
eatline();
return -1;
}
*ptr = buf;
return len;
}
else if (c1 == '\n') {
*ptr = buf;
return len;
}
if (CHAR64(c1) == XX) {
eatline();
return -1;
}
c2 = prot_getc(popd_in);
if (CHAR64(c2) == XX) {
if (c2 != '\n') eatline();
return -1;
}
c3 = prot_getc(popd_in);
if (c3 != '=' && CHAR64(c3) == XX) {
if (c3 != '\n') eatline();
return -1;
}
c4 = prot_getc(popd_in);
if (c4 != '=' && CHAR64(c4) == XX) {
if (c4 != '\n') eatline();
return -1;
}
if (len+3 >= alloc) {
alloc = len+BUFGROWSIZE;
buf = xrealloc(buf, alloc+1);
}
buf[len++] = ((CHAR64(c1)<<2) | ((CHAR64(c2)&0x30)>>4));
if (c3 == '=') {
c1 = prot_getc(popd_in);
if (c1 == '\r') c1 = prot_getc(popd_in);
if (c1 != '\n') {
eatline();
return -1;
}
if (c4 != '=') return -1;
*ptr = buf;
return len;
}
buf[len++] = (((CHAR64(c2)&0xf)<<4) | ((CHAR64(c3)&0x3c)>>2));
if (c4 == '=') {
c1 = prot_getc(popd_in);
if (c1 == '\r') c1 = prot_getc(popd_in);
if (c1 != '\n') {
eatline();
return -1;
}
*ptr = buf;
return len;
}
buf[len++] = (((CHAR64(c3)&0x3)<<6) | CHAR64(c4));
}
}
/*
* Eat characters up to and including the next newline
*/
eatline()
{
int c;
while ((c = prot_getc(popd_in)) != EOF && c != '\n');
}

File Metadata

Mime Type
text/x-c
Expires
Mon, Apr 6, 2:23 AM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18831987
Default Alt Text
pop3d.c (23 KB)

Event Timeline