2 * imap.c -- IMAP2bis/IMAP4 protocol methods
4 * Copyright 1997 by Eric S. Raymond
5 * For license terms, see the file COPYING in this directory.
12 #if defined(STDC_HEADERS)
15 #include "fetchmail.h"
20 #include <kerberosIV/des.h>
21 #include <kerberosIV/krb.h>
23 #if defined (__bsdi__)
25 #define krb_get_err_text(e) (krb_err_txt[e])
27 #if defined(__NetBSD__) || (__FreeBSD__) || defined(__linux__)
28 #define krb_get_err_text(e) (krb_err_txt[e])
32 #endif /* KERBEROS_V4 */
39 #ifdef HAVE_GSSAPI_GSSAPI_H
40 #include <gssapi/gssapi.h>
42 #ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
43 #include <gssapi/gssapi_generic.h>
45 #ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE
46 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
54 #endif /* OPIE_ENABLE */
56 #ifndef strstr /* glibc-2.1 declares this as a macro */
57 extern char *strstr(); /* needed on sysV68 R3V7.1. */
60 /* imap_version values */
61 #define IMAP2 -1 /* IMAP2 or IMAP2BIS, RFC1176 */
62 #define IMAP4 0 /* IMAP4 rev 0, RFC1730 */
63 #define IMAP4rev1 1 /* IMAP4 rev 1, RFC2060 */
65 static int imap_phase;
66 #define PHASE_GETAUTH 0
67 #define PHASE_GETRANGE 1
68 #define PHASE_GETSIZES 2
70 #define PHASE_LOGOUT 4
72 static int count, seen, recent, unseen, deletions, imap_version, preauth;
73 static int expunged, expunge_period;
74 static char capabilities[MSGBUFSIZE+1];
76 int imap_ok(int sock, char *argbuf)
77 /* parse command response */
79 char buf [MSGBUFSIZE+1];
86 if ((ok = gen_recv(sock, buf, sizeof(buf))))
89 /* all tokens in responses are caseblind */
90 for (cp = buf; *cp; cp++)
94 /* interpret untagged status responses */
95 if (strstr(buf, "* CAPABILITY"))
96 strncpy(capabilities, buf + 12, sizeof(capabilities));
97 if (strstr(buf, "EXISTS"))
99 if (strstr(buf, "RECENT"))
100 recent = atoi(buf+2);
101 if (strstr(buf, "UNSEEN"))
106 * Handle both "* 42 UNSEEN" (if tha ever happens) and
107 * "* OK [UNSEEN 42] 42". Note that what this gets us is
108 * a minimum index, not a count.
111 for (cp = buf; *cp && !isdigit(*cp); cp++)
115 if (strstr(buf, "FLAGS"))
116 seen = (strstr(buf, "SEEN") != (char *)NULL);
117 if (strstr(buf, "PREAUTH"))
120 (tag[0] != '\0' && strncmp(buf, tag, strlen(tag)));
133 for (cp = buf; !isspace(*cp); cp++)
138 if (strncmp(cp, "PREAUTH", 2) == 0)
145 else if (strncmp(cp, "OK", 2) == 0)
151 else if (strncmp(cp, "BAD", 3) == 0)
153 else if (strncmp(cp, "NO", 2) == 0)
155 if (imap_phase == PHASE_GETAUTH)
156 return(PS_AUTHFAIL); /* RFC2060, 6.2.2 */
166 static int do_otp(int sock, struct query *ctl)
170 char challenge[OPIE_CHALLENGE_MAX+1];
171 char response[OPIE_RESPONSE_MAX+1];
173 gen_send(sock, "AUTHENTICATE X-OTP");
175 if (rval = gen_recv(sock, buffer, sizeof(buffer)))
178 if ((i = from64tobits(challenge, buffer)) < 0) {
179 report(stderr, _("Could not decode initial BASE64 challenge\n"));
184 to64frombits(buffer, ctl->remotename, strlen(ctl->remotename));
186 if (outlevel >= O_MONITOR)
187 report(stdout, "IMAP> %s\n", buffer);
189 /* best not to count on the challenge code handling multiple writes */
190 strcat(buffer, "\r\n");
191 SockWrite(sock, buffer, strlen(buffer));
193 if (rval = gen_recv(sock, buffer, sizeof(buffer)))
196 if ((i = from64tobits(challenge, buffer)) < 0) {
197 report(stderr, _("Could not decode OTP challenge\n"));
201 rval = opiegenerator(challenge, !strcmp(ctl->password, "opie") ? "" : ctl->password, response);
202 if ((rval == -2) && !run.poll_interval) {
203 char secret[OPIE_SECRET_MAX+1];
204 fprintf(stderr, _("Secret pass phrase: "));
205 if (opiereadpass(secret, sizeof(secret), 0))
206 rval = opiegenerator(challenge, secret, response);
207 memset(secret, 0, sizeof(secret));
213 to64frombits(buffer, response, strlen(response));
215 if (outlevel >= O_MONITOR)
216 report(stdout, "IMAP> %s\n", buffer);
217 strcat(buffer, "\r\n");
218 SockWrite(sock, buffer, strlen(buffer));
220 if (rval = gen_recv(sock, buffer, sizeof(buffer)))
223 if (strstr(buffer, "OK"))
228 #endif /* OPIE_ENABLE */
233 #elif SIZEOF_SHORT == 4
235 #elif SIZEOF_LONG == 4
238 #error Cannot deduce a 32-bit-type
241 static int do_rfc1731(int sock, char *truename)
242 /* authenticate as per RFC1731 -- note 32-bit integer requirement here */
245 char buf1[4096], buf2[4096];
249 } challenge1, challenge2;
250 char srvinst[INST_SZ];
252 char srvrealm[REALM_SZ];
253 KTEXT_ST authenticator;
254 CREDENTIALS credentials;
255 char tktuser[MAX_K_NAME_SZ+1+INST_SZ+1+REALM_SZ+1];
256 char tktinst[INST_SZ];
257 char tktrealm[REALM_SZ];
259 des_key_schedule schedule;
261 gen_send(sock, "AUTHENTICATE KERBEROS_V4");
263 /* The data encoded in the first ready response contains a random
264 * 32-bit number in network byte order. The client should respond
265 * with a Kerberos ticket and an authenticator for the principal
266 * "imap.hostname@realm", where "hostname" is the first component
267 * of the host name of the server with all letters in lower case
268 * and where "realm" is the Kerberos realm of the server. The
269 * encrypted checksum field included within the Kerberos
270 * authenticator should contain the server provided 32-bit number
271 * in network byte order.
274 if (result = gen_recv(sock, buf1, sizeof buf1)) {
278 len = from64tobits(challenge1.cstr, buf1);
280 report(stderr, _("could not decode initial BASE64 challenge\n"));
284 /* this patch by Dan Root <dar@thekeep.org> solves an endianess
289 *(int *)tmp = ntohl(*(int *) challenge1.cstr);
290 memcpy(challenge1.cstr, tmp, sizeof(tmp));
293 /* Client responds with a Kerberos ticket and an authenticator for
294 * the principal "imap.hostname@realm" where "hostname" is the
295 * first component of the host name of the server with all letters
296 * in lower case and where "realm" is the Kerberos realm of the
297 * server. The encrypted checksum field included within the
298 * Kerberos authenticator should contain the server-provided
299 * 32-bit number in network byte order.
302 strncpy(srvinst, truename, (sizeof srvinst)-1);
303 srvinst[(sizeof srvinst)-1] = '\0';
304 for (p = srvinst; *p; p++) {
310 strncpy(srvrealm, (char *)krb_realmofhost(srvinst), (sizeof srvrealm)-1);
311 srvrealm[(sizeof srvrealm)-1] = '\0';
312 if (p = strchr(srvinst, '.')) {
316 result = krb_mk_req(&authenticator, "imap", srvinst, srvrealm, 0);
318 report(stderr, "krb_mq_req: %s\n", krb_get_err_text(result));
322 result = krb_get_cred("imap", srvinst, srvrealm, &credentials);
324 report(stderr, "krb_get_cred: %s\n", krb_get_err_text(result));
328 memcpy(session, credentials.session, sizeof session);
329 memset(&credentials, 0, sizeof credentials);
330 des_key_sched(&session, schedule);
332 result = krb_get_tf_fullname(TKT_FILE, tktuser, tktinst, tktrealm);
334 report(stderr, "krb_get_tf_fullname: %s\n", krb_get_err_text(result));
338 if (strcmp(tktuser, user) != 0) {
340 _("principal %s in ticket does not match -u %s\n"), tktuser,
347 _("non-null instance (%s) might cause strange behavior\n"),
349 strcat(tktuser, ".");
350 strcat(tktuser, tktinst);
353 if (strcmp(tktrealm, srvrealm) != 0) {
354 strcat(tktuser, "@");
355 strcat(tktuser, tktrealm);
358 result = krb_mk_req(&authenticator, "imap", srvinst, srvrealm,
361 report(stderr, "krb_mq_req: %s\n", krb_get_err_text(result));
365 to64frombits(buf1, authenticator.dat, authenticator.length);
366 if (outlevel >= O_MONITOR) {
367 report(stdout, "IMAP> %s\n", buf1);
369 strcat(buf1, "\r\n");
370 SockWrite(sock, buf1, strlen(buf1));
372 /* Upon decrypting and verifying the ticket and authenticator, the
373 * server should verify that the contained checksum field equals
374 * the original server provided random 32-bit number. Should the
375 * verification be successful, the server must add one to the
376 * checksum and construct 8 octets of data, with the first four
377 * octets containing the incremented checksum in network byte
378 * order, the fifth octet containing a bit-mask specifying the
379 * protection mechanisms supported by the server, and the sixth
380 * through eighth octets containing, in network byte order, the
381 * maximum cipher-text buffer size the server is able to receive.
382 * The server must encrypt the 8 octets of data in the session key
383 * and issue that encrypted data in a second ready response. The
384 * client should consider the server authenticated if the first
385 * four octets the un-encrypted data is equal to one plus the
386 * checksum it previously sent.
389 if (result = gen_recv(sock, buf1, sizeof buf1))
392 /* The client must construct data with the first four octets
393 * containing the original server-issued checksum in network byte
394 * order, the fifth octet containing the bit-mask specifying the
395 * selected protection mechanism, the sixth through eighth octets
396 * containing in network byte order the maximum cipher-text buffer
397 * size the client is able to receive, and the following octets
398 * containing a user name string. The client must then append
399 * from one to eight octets so that the length of the data is a
400 * multiple of eight octets. The client must then PCBC encrypt the
401 * data with the session key and respond to the second ready
402 * response with the encrypted data. The server decrypts the data
403 * and verifies the contained checksum. The username field
404 * identifies the user for whom subsequent IMAP operations are to
405 * be performed; the server must verify that the principal
406 * identified in the Kerberos ticket is authorized to connect as
407 * that user. After these verifications, the authentication
408 * process is complete.
411 len = from64tobits(buf2, buf1);
413 report(stderr, _("could not decode BASE64 ready response\n"));
417 des_ecb_encrypt((des_cblock *)buf2, (des_cblock *)buf2, schedule, 0);
418 memcpy(challenge2.cstr, buf2, 4);
419 if (ntohl(challenge2.cint) != challenge1.cint + 1) {
420 report(stderr, _("challenge mismatch\n"));
424 memset(authenticator.dat, 0, sizeof authenticator.dat);
426 result = htonl(challenge1.cint);
427 memcpy(authenticator.dat, &result, sizeof result);
429 /* The protection mechanisms and their corresponding bit-masks are as
432 * 1 No protection mechanism
433 * 2 Integrity (krb_mk_safe) protection
434 * 4 Privacy (krb_mk_priv) protection
436 authenticator.dat[4] = 1;
438 len = strlen(tktuser);
439 strncpy(authenticator.dat+8, tktuser, len);
440 authenticator.length = len + 8 + 1;
441 while (authenticator.length & 7) {
442 authenticator.length++;
444 des_pcbc_encrypt((des_cblock *)authenticator.dat,
445 (des_cblock *)authenticator.dat, authenticator.length, schedule,
448 to64frombits(buf1, authenticator.dat, authenticator.length);
449 if (outlevel >= O_MONITOR) {
450 report(stdout, "IMAP> %s\n", buf1);
453 strcat(buf1, "\r\n");
454 SockWrite(sock, buf1, strlen(buf1));
456 if (result = gen_recv(sock, buf1, sizeof buf1))
459 if (strstr(buf1, "OK")) {
466 #endif /* KERBEROS_V4 */
469 #define GSSAUTH_P_NONE 1
470 #define GSSAUTH_P_INTEGRITY 2
471 #define GSSAUTH_P_PRIVACY 4
473 static int do_gssauth(int sock, char *hostname, char *username)
475 gss_buffer_desc request_buf, send_token;
476 gss_buffer_t sec_token;
477 gss_name_t target_name;
478 gss_ctx_id_t context;
482 OM_uint32 maj_stat, min_stat;
483 char buf1[8192], buf2[8192], server_conf_flags;
484 unsigned long buf_size;
487 /* first things first: get an imap ticket for host */
488 sprintf(buf1, "imap@%s", hostname);
489 request_buf.value = buf1;
490 request_buf.length = strlen(buf1) + 1;
491 maj_stat = gss_import_name(&min_stat, &request_buf, GSS_C_NT_HOSTBASED_SERVICE,
493 if (maj_stat != GSS_S_COMPLETE) {
494 report(stderr, _("Couldn't get service name for [%s]\n"), buf1);
497 else if (outlevel >= O_DEBUG) {
498 maj_stat = gss_display_name(&min_stat, target_name, &request_buf,
500 report(stderr, _("Using service name [%s]\n"),request_buf.value);
501 maj_stat = gss_release_buffer(&min_stat, &request_buf);
504 gen_send(sock, "AUTHENTICATE GSSAPI");
506 /* upon receipt of the GSSAPI authentication request, server returns
507 * null data ready response. */
508 if (result = gen_recv(sock, buf1, sizeof buf1)) {
512 /* now start the security context initialisation loop... */
513 sec_token = GSS_C_NO_BUFFER;
514 context = GSS_C_NO_CONTEXT;
515 if (outlevel >= O_VERBOSE)
516 report(stdout, _("Sending credentials\n"));
518 send_token.length = 0;
519 send_token.value = NULL;
520 maj_stat = gss_init_sec_context(&min_stat,
525 GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
527 GSS_C_NO_CHANNEL_BINDINGS,
533 if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
534 report(stderr, _("Error exchanging credentials\n"));
535 gss_release_name(&min_stat, &target_name);
536 /* wake up server and await NO response */
537 SockWrite(sock, "\r\n", 2);
538 if (result = gen_recv(sock, buf1, sizeof buf1))
542 to64frombits(buf1, send_token.value, send_token.length);
543 gss_release_buffer(&min_stat, &send_token);
544 strcat(buf1, "\r\n");
545 SockWrite(sock, buf1, strlen(buf1));
546 if (outlevel >= O_MONITOR)
547 report(stdout, "IMAP> %s\n", buf1);
548 if (maj_stat == GSS_S_CONTINUE_NEEDED) {
549 if (result = gen_recv(sock, buf1, sizeof buf1)) {
550 gss_release_name(&min_stat, &target_name);
553 request_buf.length = from64tobits(buf2, buf1 + 2);
554 request_buf.value = buf2;
555 sec_token = &request_buf;
557 } while (maj_stat == GSS_S_CONTINUE_NEEDED);
558 gss_release_name(&min_stat, &target_name);
560 /* get security flags and buffer size */
561 if (result = gen_recv(sock, buf1, sizeof buf1)) {
564 request_buf.length = from64tobits(buf2, buf1 + 2);
565 request_buf.value = buf2;
567 maj_stat = gss_unwrap(&min_stat, context, &request_buf, &send_token,
569 if (maj_stat != GSS_S_COMPLETE) {
570 report(stderr, _("Couldn't unwrap security level data\n"));
571 gss_release_buffer(&min_stat, &send_token);
574 if (outlevel >= O_DEBUG)
575 report(stdout, _("Credential exchange complete\n"));
576 /* first octet is security levels supported. We want none, for now */
577 server_conf_flags = ((char *)send_token.value)[0];
578 if ( !(((char *)send_token.value)[0] & GSSAUTH_P_NONE) ) {
579 report(stderr, _("Server requires integrity and/or privacy\n"));
580 gss_release_buffer(&min_stat, &send_token);
583 ((char *)send_token.value)[0] = 0;
584 buf_size = ntohl(*((long *)send_token.value));
585 /* we don't care about buffer size if we don't wrap data */
586 gss_release_buffer(&min_stat, &send_token);
587 if (outlevel >= O_DEBUG) {
588 report(stdout, _("Unwrapped security level flags: %s%s%s\n"),
589 server_conf_flags & GSSAUTH_P_NONE ? "N" : "-",
590 server_conf_flags & GSSAUTH_P_INTEGRITY ? "I" : "-",
591 server_conf_flags & GSSAUTH_P_PRIVACY ? "C" : "-");
592 report(stdout, _("Maximum GSS token size is %ld\n"),buf_size);
595 /* now respond in kind (hack!!!) */
596 buf_size = htonl(buf_size); /* do as they do... only matters if we do enc */
597 memcpy(buf1, &buf_size, 4);
598 buf1[0] = GSSAUTH_P_NONE;
599 strcpy(buf1+4, username); /* server decides if princ is user */
600 request_buf.length = 4 + strlen(username) + 1;
601 request_buf.value = buf1;
602 maj_stat = gss_wrap(&min_stat, context, 0, GSS_C_QOP_DEFAULT, &request_buf,
603 &cflags, &send_token);
604 if (maj_stat != GSS_S_COMPLETE) {
605 report(stderr, _("Error creating security level request\n"));
608 to64frombits(buf1, send_token.value, send_token.length);
609 if (outlevel >= O_DEBUG) {
610 report(stdout, _("Requesting authorization as %s\n"), username);
611 report(stdout, "IMAP> %s\n",buf1);
613 strcat(buf1, "\r\n");
614 SockWrite(sock, buf1, strlen(buf1));
616 /* we should be done. Get status and finish up */
617 if (result = gen_recv(sock, buf1, sizeof buf1))
619 if (strstr(buf1, "OK")) {
620 /* flush security context */
621 if (outlevel >= O_DEBUG)
622 report(stdout, _("Releasing GSS credentials\n"));
623 maj_stat = gss_delete_sec_context(&min_stat, &context, &send_token);
624 if (maj_stat != GSS_S_COMPLETE) {
625 report(stderr, _("Error releasing credentials\n"));
628 /* send_token may contain a notification to the server to flush
629 * credentials. RFC 1731 doesn't specify what to do, and since this
630 * support is only for authentication, we'll assume the server
631 * knows enough to flush its own credentials */
632 gss_release_buffer(&min_stat, &send_token);
640 static void hmac_md5 (unsigned char *password, size_t pass_len,
641 unsigned char *challenge, size_t chal_len,
642 unsigned char *response, size_t resp_len)
645 unsigned char ipad[64];
646 unsigned char opad[64];
647 unsigned char hash_passwd[16];
654 if (pass_len > sizeof (ipad))
657 MD5Update (&ctx, password, pass_len);
658 MD5Final (hash_passwd, &ctx);
659 password = hash_passwd; pass_len = sizeof (hash_passwd);
662 memset (ipad, 0, sizeof (ipad));
663 memset (opad, 0, sizeof (opad));
664 memcpy (ipad, password, pass_len);
665 memcpy (opad, password, pass_len);
667 for (i=0; i<64; i++) {
673 MD5Update (&ctx, ipad, sizeof (ipad));
674 MD5Update (&ctx, challenge, chal_len);
675 MD5Final (response, &ctx);
678 MD5Update (&ctx, opad, sizeof (opad));
679 MD5Update (&ctx, response, resp_len);
680 MD5Final (response, &ctx);
686 static tSmbNtlmAuthRequest request;
687 static tSmbNtlmAuthChallenge challenge;
688 static tSmbNtlmAuthResponse response;
691 * NTLM support by Grant Edwards.
693 * Handle MS-Exchange NTLM authentication method. This is the same
694 * as the NTLM auth used by Samba for SMB related services. We just
695 * encode the packets in base64 instead of sending them out via a
698 * Much source (ntlm.h, smb*.c smb*.h) was borrowed from Samba.
701 static int do_imap_ntlm(int sock, struct query *ctl)
706 gen_send(sock, "AUTHENTICATE NTLM");
708 if ((result = gen_recv(sock, msgbuf, sizeof msgbuf)))
711 if (msgbuf[0] != '+')
714 buildSmbNtlmAuthRequest(&request,ctl->remotename,NULL);
716 if (outlevel >= O_DEBUG)
717 dumpSmbNtlmAuthRequest(stdout, &request);
719 memset(msgbuf,0,sizeof msgbuf);
720 to64frombits (msgbuf, (unsigned char*)&request, SmbLength(&request));
722 if (outlevel >= O_MONITOR)
723 report(stdout, "IMAP> %s\n", msgbuf);
725 strcat(msgbuf,"\r\n");
726 SockWrite (sock, msgbuf, strlen (msgbuf));
728 if ((gen_recv(sock, msgbuf, sizeof msgbuf)))
731 len = from64tobits ((unsigned char*)&challenge, msgbuf);
733 if (outlevel >= O_DEBUG)
734 dumpSmbNtlmAuthChallenge(stdout, &challenge);
736 buildSmbNtlmAuthResponse(&challenge, &response,ctl->remotename,ctl->password);
738 if (outlevel >= O_DEBUG)
739 dumpSmbNtlmAuthResponse(stdout, &response);
741 memset(msgbuf,0,sizeof msgbuf);
742 to64frombits (msgbuf, (unsigned char*)&response, SmbLength(&response));
744 if (outlevel >= O_MONITOR)
745 report(stdout, "IMAP> %s\n", msgbuf);
747 strcat(msgbuf,"\r\n");
749 SockWrite (sock, msgbuf, strlen (msgbuf));
751 if ((result = gen_recv (sock, msgbuf, sizeof msgbuf)))
754 if (strstr (msgbuf, "OK"))
761 static int do_cram_md5 (int sock, struct query *ctl)
762 /* authenticate as per RFC2195 */
766 unsigned char buf1[1024];
767 unsigned char msg_id[768];
768 unsigned char response[16];
769 unsigned char reply[1024];
771 gen_send (sock, "AUTHENTICATE CRAM-MD5");
774 * The data encoded in the first ready response contains an
775 * presumptively arbitrary string of random digits, a timestamp, and the
776 * fully-qualified primary host name of the server. The syntax of the
777 * unencoded form must correspond to that of an RFC 822 'msg-id'
778 * [RFC822] as described in [POP3].
781 if ((result = gen_recv (sock, buf1, sizeof (buf1)))) {
785 len = from64tobits (msg_id, buf1);
787 report (stderr, _("could not decode BASE64 challenge\n"));
789 } else if (len < sizeof (msg_id)) {
792 msg_id[sizeof (msg_id)-1] = 0;
794 if (outlevel >= O_DEBUG) {
795 report (stdout, "decoded as %s\n", msg_id);
798 /* The client makes note of the data and then responds with a string
799 * consisting of the user name, a space, and a 'digest'. The latter is
800 * computed by applying the keyed MD5 algorithm from [KEYED-MD5] where
801 * the key is a shared secret and the digested text is the timestamp
802 * (including angle-brackets).
805 hmac_md5 (ctl->password, strlen (ctl->password),
806 msg_id, strlen (msg_id),
807 response, sizeof (response));
810 snprintf (reply, sizeof (reply),
814 "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
816 response[0], response[1], response[2], response[3],
817 response[4], response[5], response[6], response[7],
818 response[8], response[9], response[10], response[11],
819 response[12], response[13], response[14], response[15]);
821 if (outlevel >= O_DEBUG) {
822 report (stdout, "replying with %s\n", reply);
825 to64frombits (buf1, reply, strlen (reply));
826 if (outlevel >= O_MONITOR) {
827 report (stdout, "IMAP> %s\n", buf1);
830 /* PMDF5.2 IMAP has a bug that requires this to be a single write */
831 strcat (buf1, "\r\n");
832 SockWrite (sock, buf1, strlen (buf1));
834 if ((result = gen_recv (sock, buf1, sizeof (buf1))))
837 if (strstr (buf1, "OK")) {
844 int imap_canonicalize(char *result, char *raw, int maxlen)
845 /* encode an IMAP password as per RFC1730's quoting conventions */
850 for (i = 0; i < strlen(raw) && i < maxlen; i++)
852 if ((raw[i] == '\\') || (raw[i] == '"'))
854 result[j++] = raw[i];
861 int imap_getauth(int sock, struct query *ctl, char *greeting)
862 /* apply for connection authorization */
866 imap_phase = PHASE_GETAUTH;
868 /* probe to see if we're running IMAP4 and can use RFC822.PEEK */
869 capabilities[0] = '\0';
870 if ((ok = gen_transact(sock, "CAPABILITY")) == PS_SUCCESS)
872 /* UW-IMAP server 10.173 notifies in all caps */
873 if (strstr(capabilities, "IMAP4REV1"))
875 imap_version = IMAP4rev1;
876 if (outlevel >= O_DEBUG)
877 report(stdout, _("Protocol identified as IMAP4 rev 1\n"));
881 imap_version = IMAP4;
882 if (outlevel >= O_DEBUG)
883 report(stdout, _("Protocol identified as IMAP4 rev 0\n"));
886 else if (ok == PS_ERROR)
888 imap_version = IMAP2;
889 if (outlevel >= O_DEBUG)
890 report(stdout, _("Protocol identified as IMAP2 or IMAP2BIS\n"));
895 peek_capable = (imap_version >= IMAP4);
898 * Assumption: expunges are cheap, so we want to do them
899 * after every message unless user said otherwise.
901 if (NUM_SPECIFIED(ctl->expunge))
902 expunge_period = NUM_VALUE_OUT(ctl->expunge);
910 if ((ctl->server.protocol == P_IMAP) && strstr(capabilities, "AUTH=X-OTP"))
912 if (outlevel >= O_DEBUG)
913 report(stdout, _("OTP authentication is supported\n"));
914 if (do_otp(sock, ctl) == PS_SUCCESS)
917 #endif /* OPIE_ENABLE */
920 if (strstr(capabilities, "AUTH=GSSAPI"))
922 if (ctl->server.protocol == P_IMAP_GSS)
924 if (outlevel >= O_DEBUG)
925 report(stdout, _("GSS authentication is supported\n"));
926 return do_gssauth(sock, ctl->server.truename, ctl->remotename);
929 else if (ctl->server.protocol == P_IMAP_GSS)
932 _("Required GSS capability not supported by server\n"));
938 if (strstr(capabilities, "AUTH=KERBEROS_V4"))
940 if (outlevel >= O_DEBUG)
941 report(stdout, _("KERBEROS_V4 authentication is supported\n"));
943 if (ctl->server.protocol == P_IMAP_K4)
945 if ((ok = do_rfc1731(sock, ctl->server.truename)))
947 if (outlevel >= O_MONITOR)
948 report(stdout, "IMAP> *\n");
949 SockWrite(sock, "*\r\n", 3);
954 /* else fall through to ordinary AUTH=LOGIN case */
956 else if (ctl->server.protocol == P_IMAP_K4)
959 _("Required KERBEROS_V4 capability not supported by server\n"));
962 #endif /* KERBEROS_V4 */
964 if (strstr(capabilities, "AUTH=CRAM-MD5"))
966 if (outlevel >= O_DEBUG)
967 report (stdout, _("CRAM-MD5 authentication is supported\n"));
968 if (ctl->server.protocol != P_IMAP_LOGIN)
970 if ((ok = do_cram_md5 (sock, ctl)))
972 if (outlevel >= O_MONITOR)
973 report (stdout, "IMAP> *\n");
974 SockWrite (sock, "*\r\n", 3);
979 else if (ctl->server.protocol == P_IMAP_CRAM_MD5)
982 _("Required CRAM-MD5 capability not supported by server\n"));
987 if (strstr (capabilities, "AUTH=NTLM"))
989 if (outlevel >= O_DEBUG)
990 report (stdout, _("NTLM authentication is supported\n"));
991 return do_imap_ntlm (sock, ctl);
993 #endif /* NTLM_ENABLE */
995 #ifdef __UNUSED__ /* The Cyrus IMAP4rev1 server chokes on this */
996 /* this handles either AUTH=LOGIN or AUTH-LOGIN */
997 if ((imap_version >= IMAP4rev1) && (!strstr(capabilities, "LOGIN"))) {
999 _("Required LOGIN capability not supported by server\n"));
1002 #endif /* __UNUSED__ */
1005 /* these sizes guarantee no buffer overflow */
1006 char remotename[NAMELEN*2+1], password[PASSWORDLEN*2+1];
1008 imap_canonicalize(remotename, ctl->remotename, NAMELEN);
1009 imap_canonicalize(password, ctl->password, PASSWORDLEN);
1010 ok = gen_transact(sock, "LOGIN \"%s\" \"%s\"", remotename, password);
1019 static int internal_expunge(int sock)
1020 /* ship an expunge, resetting associated counters */
1024 if ((ok = gen_transact(sock, "EXPUNGE")))
1027 expunged += deletions;
1030 #ifdef IMAP_UID /* not used */
1032 #endif /* IMAP_UID */
1037 static int imap_getrange(int sock,
1040 int *countp, int *newp, int *bytes)
1041 /* get range of messages to be fetched */
1045 imap_phase = PHASE_GETRANGE;
1047 /* find out how many messages are waiting */
1048 *bytes = recent = unseen = -1;
1053 * We have to have an expunge here, otherwise the re-poll will
1054 * infinite-loop picking up un-expunged messages -- unless the
1055 * expunge period is one and we've been nuking each message
1056 * just after deletion.
1059 if (deletions && expunge_period != 1)
1060 internal_expunge(sock);
1062 if (ok || gen_transact(sock, "NOOP"))
1064 report(stderr, _("re-poll failed\n"));
1067 else if (count == -1) /* no EXISTS response to NOOP */
1076 ok = gen_transact(sock, "SELECT %s", folder ? folder : "INBOX");
1078 ok = gen_transact(sock, "EXAMINE %s", folder ? folder : "INBOX");
1081 report(stderr, _("mailbox selection failed\n"));
1089 * Note: because IMAP has an is_old method, this number is used
1090 * only for the "X messages (Y unseen)" notification. Accordingly
1091 * it doesn't matter much that it can be wrong (e.g. if we see an
1092 * UNSEEN response but not all messages above the first UNSEEN one
1095 if (unseen >= 0) /* optional, but better if we see it */
1096 *newp = count - unseen + 1;
1097 else if (recent >= 0) /* mandatory */
1100 *newp = -1; /* should never happen, RECENT is mandatory */
1107 static int imap_getsizes(int sock, int count, int *sizes)
1108 /* capture the sizes of all messages */
1110 char buf [MSGBUFSIZE+1];
1112 imap_phase = PHASE_GETSIZES;
1115 * Some servers (as in, PMDF5.1-9.1 under OpenVMS 6.1)
1116 * won't accept 1:1 as valid set syntax. Some implementors
1117 * should be taken out and shot for excessive anality.
1120 gen_send(sock, "FETCH 1 RFC822.SIZE", count);
1122 gen_send(sock, "FETCH 1:%d RFC822.SIZE", count);
1127 if ((ok = gen_recv(sock, buf, sizeof(buf))))
1129 if (strstr(buf, "OK"))
1131 else if (sscanf(buf, "* %d FETCH (RFC822.SIZE %d)", &num, &size) == 2)
1132 sizes[num - 1] = size;
1135 imap_phase = PHASE_FETCH;
1140 static int imap_is_old(int sock, struct query *ctl, int number)
1141 /* is the given message old? */
1145 /* expunges change the fetch numbers */
1148 if ((ok = gen_transact(sock, "FETCH %d FLAGS", number)) != 0)
1154 static int imap_fetch_headers(int sock, struct query *ctl,int number,int *lenp)
1155 /* request headers of nth message */
1157 char buf [MSGBUFSIZE+1];
1160 /* expunges change the fetch numbers */
1164 * This is blessed by RFC1176, RFC1730, RFC2060.
1165 * According to the RFCs, it should *not* set the \Seen flag.
1167 gen_send(sock, "FETCH %d RFC822.HEADER", number);
1169 /* looking for FETCH response */
1173 if ((ok = gen_recv(sock, buf, sizeof(buf))))
1176 (sscanf(buf+2, "%d FETCH (%*s {%d}", &num, lenp) != 2);
1184 static int imap_fetch_body(int sock, struct query *ctl, int number, int *lenp)
1185 /* request body of nth message */
1187 char buf [MSGBUFSIZE+1], *cp;
1190 /* expunges change the fetch numbers */
1194 * If we're using IMAP4, we can fetch the message without setting its
1195 * seen flag. This is good! It means that if the protocol exchange
1196 * craps out during the message, it will still be marked `unseen' on
1199 * However...*don't* do this if we're using keep to suppress deletion!
1200 * In that case, marking the seen flag is the only way to prevent the
1201 * message from being re-fetched on subsequent runs (and according
1202 * to RFC2060 p.43 this fetch should set Seen as a side effect).
1204 switch (imap_version)
1206 case IMAP4rev1: /* RFC 2060 */
1208 gen_send(sock, "FETCH %d BODY.PEEK[TEXT]", number);
1210 gen_send(sock, "FETCH %d BODY[TEXT]", number);
1213 case IMAP4: /* RFC 1730 */
1215 gen_send(sock, "FETCH %d RFC822.TEXT.PEEK", number);
1217 gen_send(sock, "FETCH %d RFC822.TEXT", number);
1220 default: /* RFC 1176 */
1221 gen_send(sock, "FETCH %d RFC822.TEXT", number);
1225 /* looking for FETCH response */
1229 if ((ok = gen_recv(sock, buf, sizeof(buf))))
1232 (!strstr(buf+4, "FETCH") || sscanf(buf+2, "%d", &num) != 1);
1238 * Try to extract a length from the FETCH response. RFC2060 requires
1239 * it to be present, but at least one IMAP server (Novell GroupWise)
1242 if ((cp = strchr(buf, '{')))
1243 *lenp = atoi(cp + 1);
1245 *lenp = -1; /* missing length part in FETCH reponse */
1250 static int imap_trail(int sock, struct query *ctl, int number)
1251 /* discard tail of FETCH response after reading message text */
1253 /* expunges change the fetch numbers */
1254 /* number -= expunged; */
1258 char buf[MSGBUFSIZE+1];
1261 if ((ok = gen_recv(sock, buf, sizeof(buf))))
1264 /* UW IMAP returns "OK FETCH", Cyrus returns "OK Completed" */
1265 if (strstr(buf, "OK"))
1270 * Any IMAP server that fails to set Seen on a BODY[TEXT]
1271 * fetch violates RFC2060 p.43 (top). This becomes an issue
1272 * when keep is on, because seen messages aren't deleted and
1273 * get refetched on each poll. As a workaround, if keep is on
1274 * we can set the Seen flag explicitly.
1276 * This code isn't used yet because we don't know of any IMAP
1277 * servers broken in this way.
1280 if ((ok = gen_transact(sock,
1281 imap_version == IMAP4
1282 ? "STORE %d +FLAGS.SILENT (\\Seen)"
1283 : "STORE %d +FLAGS (\\Seen)",
1286 #endif /* __UNUSED__ */
1292 static int imap_delete(int sock, struct query *ctl, int number)
1293 /* set delete flag for given message */
1297 /* expunges change the fetch numbers */
1301 * Use SILENT if possible as a minor throughput optimization.
1302 * Note: this has been dropped from IMAP4rev1.
1304 * We set Seen because there are some IMAP servers (notably HP
1305 * OpenMail) that do message-receipt DSNs, but only when the seen
1306 * bit is set. This is the appropriate time -- we get here right
1307 * after the local SMTP response that says delivery was
1310 if ((ok = gen_transact(sock,
1311 imap_version == IMAP4
1312 ? "STORE %d +FLAGS.SILENT (\\Seen \\Deleted)"
1313 : "STORE %d +FLAGS (\\Seen \\Deleted)",
1320 * We do an expunge after expunge_period messages, rather than
1321 * just before quit, so that a line hit during a long session
1322 * won't result in lots of messages being fetched again during
1325 if (NUM_NONZERO(expunge_period) && (deletions % expunge_period) == 0)
1326 internal_expunge(sock);
1331 static int imap_logout(int sock, struct query *ctl)
1332 /* send logout command */
1334 imap_phase = PHASE_LOGOUT;
1336 /* if any un-expunged deletions remain, ship an expunge now */
1338 internal_expunge(sock);
1340 return(gen_transact(sock, "LOGOUT"));
1343 const static struct method imap =
1345 "IMAP", /* Internet Message Access Protocol */
1349 #else /* INET6_ENABLE */
1350 143, /* standard IMAP2bis/IMAP4 port */
1351 993, /* ssl IMAP2bis/IMAP4 port */
1352 #endif /* INET6_ENABLE */
1353 TRUE, /* this is a tagged protocol */
1354 FALSE, /* no message delimiter */
1355 imap_ok, /* parse command response */
1356 imap_canonicalize, /* deal with embedded slashes and spaces */
1357 imap_getauth, /* get authorization */
1358 imap_getrange, /* query range of messages */
1359 imap_getsizes, /* get sizes of messages (used for ESMTP SIZE option) */
1360 imap_is_old, /* no UID check */
1361 imap_fetch_headers, /* request given message headers */
1362 imap_fetch_body, /* request given message body */
1363 imap_trail, /* eat message trailer */
1364 imap_delete, /* delete the message */
1365 imap_logout, /* expunge and exit */
1366 TRUE, /* yes, we can re-poll */
1369 int doIMAP(struct query *ctl)
1370 /* retrieve messages using IMAP Version 2bis or Version 4 */
1372 return(do_protocol(ctl, &imap));
1375 /* imap.c ends here */