drv_imap.c 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816
  1. /*
  2. * mbsync - mailbox synchronizer
  3. * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
  4. * Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
  5. * Copyright (C) 2004 Theodore Y. Ts'o <tytso@mit.edu>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. * As a special exception, mbsync may be linked with the OpenSSL library,
  22. * despite that library's more restrictive license.
  23. */
  24. #include "isync.h"
  25. #include <assert.h>
  26. #include <unistd.h>
  27. #include <sys/mman.h>
  28. #include <sys/time.h>
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <stddef.h>
  32. #include <errno.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35. #include <sys/socket.h>
  36. #include <sys/ioctl.h>
  37. #include <netinet/in.h>
  38. #include <netinet/tcp.h>
  39. #include <arpa/inet.h>
  40. #include <netdb.h>
  41. #if HAVE_LIBSSL
  42. # include <openssl/ssl.h>
  43. # include <openssl/err.h>
  44. # include <openssl/hmac.h>
  45. #endif
  46. typedef struct imap_server_conf {
  47. struct imap_server_conf *next;
  48. char *name;
  49. char *tunnel;
  50. char *host;
  51. int port;
  52. char *user;
  53. char *pass;
  54. #if HAVE_LIBSSL
  55. char *cert_file;
  56. unsigned use_imaps:1;
  57. unsigned require_ssl:1;
  58. unsigned use_sslv2:1;
  59. unsigned use_sslv3:1;
  60. unsigned use_tlsv1:1;
  61. unsigned require_cram:1;
  62. #endif
  63. } imap_server_conf_t;
  64. typedef struct imap_store_conf {
  65. store_conf_t gen;
  66. imap_server_conf_t *server;
  67. unsigned use_namespace:1;
  68. } imap_store_conf_t;
  69. typedef struct imap_message {
  70. message_t gen;
  71. /* int seq; will be needed when expunges are tracked */
  72. } imap_message_t;
  73. #define NIL (void*)0x1
  74. #define LIST (void*)0x2
  75. typedef struct _list {
  76. struct _list *next, *child;
  77. char *val;
  78. int len;
  79. } list_t;
  80. typedef struct {
  81. int fd;
  82. #if HAVE_LIBSSL
  83. SSL *ssl;
  84. unsigned int use_ssl:1;
  85. #endif
  86. } Socket_t;
  87. typedef struct {
  88. Socket_t sock;
  89. int bytes;
  90. int offset;
  91. char buf[1024];
  92. } buffer_t;
  93. struct imap_cmd;
  94. #define max_in_progress 50 /* make this configurable? */
  95. typedef struct imap {
  96. int uidnext; /* from SELECT responses */
  97. list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */
  98. string_list_t *boxes; /* LIST results */
  99. message_t **msgapp; /* FETCH results */
  100. unsigned caps, rcaps; /* CAPABILITY results */
  101. /* command queue */
  102. int nexttag, num_in_progress, literal_pending;
  103. struct imap_cmd *in_progress, **in_progress_append;
  104. #if HAVE_LIBSSL
  105. SSL_CTX *SSLContext;
  106. #endif
  107. buffer_t buf; /* this is BIG, so put it last */
  108. } imap_t;
  109. typedef struct imap_store {
  110. store_t gen;
  111. imap_t *imap;
  112. const char *prefix;
  113. unsigned /*currentnc:1,*/ trashnc:1;
  114. } imap_store_t;
  115. struct imap_cmd_cb {
  116. int (*cont)( imap_store_t *ctx, struct imap_cmd *cmd, const char *prompt );
  117. void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response);
  118. void *ctx;
  119. char *data;
  120. int dlen;
  121. int uid;
  122. unsigned create:1, trycreate:1;
  123. };
  124. struct imap_cmd {
  125. struct imap_cmd *next;
  126. struct imap_cmd_cb cb;
  127. char *cmd;
  128. int tag;
  129. };
  130. #define CAP(cap) (imap->caps & (1 << (cap)))
  131. enum CAPABILITY {
  132. NOLOGIN = 0,
  133. UIDPLUS,
  134. LITERALPLUS,
  135. NAMESPACE,
  136. #if HAVE_LIBSSL
  137. CRAM,
  138. STARTTLS,
  139. #endif
  140. };
  141. static const char *cap_list[] = {
  142. "LOGINDISABLED",
  143. "UIDPLUS",
  144. "LITERAL+",
  145. "NAMESPACE",
  146. #if HAVE_LIBSSL
  147. "AUTH=CRAM-MD5",
  148. "STARTTLS",
  149. #endif
  150. };
  151. #define RESP_OK 0
  152. #define RESP_NO 1
  153. #define RESP_BAD 2
  154. static int get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd );
  155. static const char *Flags[] = {
  156. "\\Draft",
  157. "\\Flagged",
  158. "\\Answered",
  159. "\\Seen",
  160. "\\Deleted",
  161. };
  162. #if HAVE_LIBSSL
  163. /* this gets called when a certificate is to be verified */
  164. static int
  165. verify_cert( SSL *ssl )
  166. {
  167. X509 *cert;
  168. int err;
  169. char buf[256];
  170. int ret = -1;
  171. BIO *bio;
  172. cert = SSL_get_peer_certificate( ssl );
  173. if (!cert) {
  174. fprintf( stderr, "Error, no server certificate\n" );
  175. return -1;
  176. }
  177. err = SSL_get_verify_result( ssl );
  178. if (err == X509_V_OK)
  179. return 0;
  180. fprintf( stderr, "Error, can't verify certificate: %s (%d)\n",
  181. X509_verify_cert_error_string(err), err );
  182. X509_NAME_oneline( X509_get_subject_name( cert ), buf, sizeof(buf) );
  183. info( "\nSubject: %s\n", buf );
  184. X509_NAME_oneline( X509_get_issuer_name( cert ), buf, sizeof(buf) );
  185. info( "Issuer: %s\n", buf );
  186. bio = BIO_new( BIO_s_mem() );
  187. ASN1_TIME_print( bio, X509_get_notBefore( cert ) );
  188. memset( buf, 0, sizeof(buf) );
  189. BIO_read( bio, buf, sizeof(buf) - 1 );
  190. info( "Valid from: %s\n", buf );
  191. ASN1_TIME_print( bio, X509_get_notAfter( cert ) );
  192. memset( buf, 0, sizeof(buf) );
  193. BIO_read( bio, buf, sizeof(buf) - 1 );
  194. BIO_free( bio );
  195. info( " to: %s\n", buf );
  196. fputs( "\n*** WARNING *** There is no way to verify this certificate. It is\n"
  197. " possible that a hostile attacker has replaced the\n"
  198. " server certificate. Continue at your own risk!\n"
  199. "\nAccept this certificate anyway? [no]: ", stderr );
  200. if (fgets( buf, sizeof(buf), stdin ) && (buf[0] == 'y' || buf[0] == 'Y')) {
  201. ret = 0;
  202. fprintf( stderr, "\n*** Fine, but don't say I didn't warn you!\n\n" );
  203. }
  204. return ret;
  205. }
  206. static int
  207. init_ssl_ctx( imap_store_t *ctx )
  208. {
  209. imap_t *imap = ctx->imap;
  210. imap_store_conf_t *conf = (imap_store_conf_t *)ctx->gen.conf;
  211. imap_server_conf_t *srvc = conf->server;
  212. SSL_METHOD *method;
  213. int options = 0;
  214. if (srvc->use_tlsv1 && !srvc->use_sslv2 && !srvc->use_sslv3)
  215. method = TLSv1_client_method();
  216. else
  217. method = SSLv23_client_method();
  218. imap->SSLContext = SSL_CTX_new( method );
  219. if (!srvc->cert_file) {
  220. fprintf( stderr, "Error, CertificateFile not defined\n" );
  221. return -1;
  222. } else if (access( srvc->cert_file, R_OK ))
  223. warn( "*** Warning: can't read CertificateFile, so can't verify server certificates\n" );
  224. else if (!SSL_CTX_load_verify_locations( imap->SSLContext, srvc->cert_file, NULL )) {
  225. fprintf( stderr, "Error, SSL_CTX_load_verify_locations: %s\n",
  226. ERR_error_string( ERR_get_error(), 0 ) );
  227. return -1;
  228. }
  229. if (!srvc->use_sslv2)
  230. options |= SSL_OP_NO_SSLv2;
  231. if (!srvc->use_sslv3)
  232. options |= SSL_OP_NO_SSLv3;
  233. if (!srvc->use_tlsv1)
  234. options |= SSL_OP_NO_TLSv1;
  235. SSL_CTX_set_options( imap->SSLContext, options );
  236. /* we check the result of the verification after SSL_connect() */
  237. SSL_CTX_set_verify( imap->SSLContext, SSL_VERIFY_NONE, 0 );
  238. return 0;
  239. }
  240. #endif /* HAVE_LIBSSL */
  241. static void
  242. socket_perror( const char *func, Socket_t *sock, int ret )
  243. {
  244. #if HAVE_LIBSSL
  245. int err;
  246. if (sock->use_ssl) {
  247. switch ((err = SSL_get_error( sock->ssl, ret ))) {
  248. case SSL_ERROR_SYSCALL:
  249. case SSL_ERROR_SSL:
  250. if ((err = ERR_get_error()) == 0) {
  251. if (ret == 0)
  252. fprintf( stderr, "SSL_%s:got EOF\n", func );
  253. else
  254. fprintf( stderr, "SSL_%s:%d:%s\n", func, errno, strerror(errno) );
  255. } else
  256. fprintf( stderr, "SSL_%s:%d:%s\n", func, err, ERR_error_string( err, 0 ) );
  257. return;
  258. default:
  259. fprintf( stderr, "SSL_%s:%d:unhandled SSL error\n", func, err );
  260. break;
  261. }
  262. return;
  263. }
  264. #else
  265. (void)sock;
  266. #endif
  267. if (ret < 0)
  268. perror( func );
  269. else
  270. fprintf( stderr, "%s: unexpected EOF\n", func );
  271. }
  272. static int
  273. socket_read( Socket_t *sock, char *buf, int len )
  274. {
  275. int n =
  276. #if HAVE_LIBSSL
  277. sock->use_ssl ? SSL_read( sock->ssl, buf, len ) :
  278. #endif
  279. read( sock->fd, buf, len );
  280. if (n <= 0) {
  281. socket_perror( "read", sock, n );
  282. close( sock->fd );
  283. sock->fd = -1;
  284. }
  285. return n;
  286. }
  287. static int
  288. socket_write( Socket_t *sock, char *buf, int len )
  289. {
  290. int n =
  291. #if HAVE_LIBSSL
  292. sock->use_ssl ? SSL_write( sock->ssl, buf, len ) :
  293. #endif
  294. write( sock->fd, buf, len );
  295. if (n != len) {
  296. socket_perror( "write", sock, n );
  297. close( sock->fd );
  298. sock->fd = -1;
  299. }
  300. return n;
  301. }
  302. static int
  303. socket_pending( Socket_t *sock )
  304. {
  305. int num = -1;
  306. if (ioctl( sock->fd, FIONREAD, &num ) < 0)
  307. return -1;
  308. if (num > 0)
  309. return num;
  310. #if HAVE_LIBSSL
  311. if (sock->use_ssl)
  312. return SSL_pending( sock->ssl );
  313. #endif
  314. return 0;
  315. }
  316. /* simple line buffering */
  317. static int
  318. buffer_gets( buffer_t * b, char **s )
  319. {
  320. int n;
  321. int start = b->offset;
  322. *s = b->buf + start;
  323. for (;;) {
  324. /* make sure we have enough data to read the \r\n sequence */
  325. if (b->offset + 1 >= b->bytes) {
  326. if (start) {
  327. /* shift down used bytes */
  328. *s = b->buf;
  329. assert( start <= b->bytes );
  330. n = b->bytes - start;
  331. if (n)
  332. memcpy( b->buf, b->buf + start, n );
  333. b->offset -= start;
  334. b->bytes = n;
  335. start = 0;
  336. }
  337. n = socket_read( &b->sock, b->buf + b->bytes,
  338. sizeof(b->buf) - b->bytes );
  339. if (n <= 0)
  340. return -1;
  341. b->bytes += n;
  342. }
  343. if (b->buf[b->offset] == '\r') {
  344. assert( b->offset + 1 < b->bytes );
  345. if (b->buf[b->offset + 1] == '\n') {
  346. b->buf[b->offset] = 0; /* terminate the string */
  347. b->offset += 2; /* next line */
  348. if (Verbose)
  349. puts( *s );
  350. return 0;
  351. }
  352. }
  353. b->offset++;
  354. }
  355. /* not reached */
  356. }
  357. static struct imap_cmd *
  358. v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb,
  359. const char *fmt, va_list ap )
  360. {
  361. imap_t *imap = ctx->imap;
  362. struct imap_cmd *cmd;
  363. int n, bufl;
  364. char buf[1024];
  365. cmd = nfmalloc( sizeof(struct imap_cmd) );
  366. nfvasprintf( &cmd->cmd, fmt, ap );
  367. cmd->tag = ++imap->nexttag;
  368. if (cb)
  369. cmd->cb = *cb;
  370. else
  371. memset( &cmd->cb, 0, sizeof(cmd->cb) );
  372. while (imap->literal_pending)
  373. get_cmd_result( ctx, 0 );
  374. bufl = nfsnprintf( buf, sizeof(buf), cmd->cb.data ? CAP(LITERALPLUS) ?
  375. "%d %s{%d+}\r\n" : "%d %s{%d}\r\n" : "%d %s\r\n",
  376. cmd->tag, cmd->cmd, cmd->cb.dlen );
  377. if (Verbose) {
  378. if (imap->num_in_progress)
  379. printf( "(%d in progress) ", imap->num_in_progress );
  380. if (memcmp( cmd->cmd, "LOGIN", 5 ))
  381. printf( ">>> %s", buf );
  382. else
  383. printf( ">>> %d LOGIN <user> <pass>\n", cmd->tag );
  384. }
  385. if (socket_write( &imap->buf.sock, buf, bufl ) != bufl) {
  386. free( cmd->cmd );
  387. free( cmd );
  388. if (cb && cb->data)
  389. free( cb->data );
  390. return NULL;
  391. }
  392. if (cmd->cb.data) {
  393. if (CAP(LITERALPLUS)) {
  394. n = socket_write( &imap->buf.sock, cmd->cb.data, cmd->cb.dlen );
  395. free( cmd->cb.data );
  396. if (n != cmd->cb.dlen ||
  397. (n = socket_write( &imap->buf.sock, "\r\n", 2 )) != 2)
  398. {
  399. free( cmd->cmd );
  400. free( cmd );
  401. return NULL;
  402. }
  403. cmd->cb.data = 0;
  404. } else
  405. imap->literal_pending = 1;
  406. } else if (cmd->cb.cont)
  407. imap->literal_pending = 1;
  408. cmd->next = 0;
  409. *imap->in_progress_append = cmd;
  410. imap->in_progress_append = &cmd->next;
  411. imap->num_in_progress++;
  412. return cmd;
  413. }
  414. static struct imap_cmd *
  415. issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... )
  416. {
  417. struct imap_cmd *ret;
  418. va_list ap;
  419. va_start( ap, fmt );
  420. ret = v_issue_imap_cmd( ctx, cb, fmt, ap );
  421. va_end( ap );
  422. return ret;
  423. }
  424. static struct imap_cmd *
  425. issue_imap_cmd_w( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... )
  426. {
  427. imap_t *imap = ctx->imap;
  428. struct imap_cmd *ret;
  429. va_list ap;
  430. va_start( ap, fmt );
  431. ret = v_issue_imap_cmd( ctx, cb, fmt, ap );
  432. va_end( ap );
  433. while (imap->num_in_progress > max_in_progress ||
  434. socket_pending( &imap->buf.sock ))
  435. get_cmd_result( ctx, 0 );
  436. return ret;
  437. }
  438. static int
  439. imap_exec( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... )
  440. {
  441. va_list ap;
  442. struct imap_cmd *cmdp;
  443. va_start( ap, fmt );
  444. cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap );
  445. va_end( ap );
  446. if (!cmdp)
  447. return RESP_BAD;
  448. return get_cmd_result( ctx, cmdp );
  449. }
  450. static int
  451. imap_exec_b( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... )
  452. {
  453. va_list ap;
  454. struct imap_cmd *cmdp;
  455. va_start( ap, fmt );
  456. cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap );
  457. va_end( ap );
  458. if (!cmdp)
  459. return DRV_STORE_BAD;
  460. switch (get_cmd_result( ctx, cmdp )) {
  461. case RESP_BAD: return DRV_STORE_BAD;
  462. case RESP_NO: return DRV_BOX_BAD;
  463. default: return DRV_OK;
  464. }
  465. }
  466. static int
  467. imap_exec_m( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... )
  468. {
  469. va_list ap;
  470. struct imap_cmd *cmdp;
  471. va_start( ap, fmt );
  472. cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap );
  473. va_end( ap );
  474. if (!cmdp)
  475. return DRV_STORE_BAD;
  476. switch (get_cmd_result( ctx, cmdp )) {
  477. case RESP_BAD: return DRV_STORE_BAD;
  478. case RESP_NO: return DRV_MSG_BAD;
  479. default: return DRV_OK;
  480. }
  481. }
  482. /*
  483. static void
  484. drain_imap_replies( imap_t *imap )
  485. {
  486. while (imap->num_in_progress)
  487. get_cmd_result( imap, 0 );
  488. }
  489. */
  490. static int
  491. is_atom( list_t *list )
  492. {
  493. return list && list->val && list->val != NIL && list->val != LIST;
  494. }
  495. static int
  496. is_list( list_t *list )
  497. {
  498. return list && list->val == LIST;
  499. }
  500. static void
  501. free_list( list_t *list )
  502. {
  503. list_t *tmp;
  504. for (; list; list = tmp) {
  505. tmp = list->next;
  506. if (is_list( list ))
  507. free_list( list->child );
  508. else if (is_atom( list ))
  509. free( list->val );
  510. free( list );
  511. }
  512. }
  513. static int
  514. parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level )
  515. {
  516. list_t *cur;
  517. char *s = *sp, *p;
  518. int n, bytes;
  519. for (;;) {
  520. while (isspace( (unsigned char)*s ))
  521. s++;
  522. if (level && *s == ')') {
  523. s++;
  524. break;
  525. }
  526. *curp = cur = nfmalloc( sizeof(*cur) );
  527. curp = &cur->next;
  528. cur->val = 0; /* for clean bail */
  529. if (*s == '(') {
  530. /* sublist */
  531. s++;
  532. cur->val = LIST;
  533. if (parse_imap_list_l( imap, &s, &cur->child, level + 1 ))
  534. goto bail;
  535. } else if (imap && *s == '{') {
  536. /* literal */
  537. bytes = cur->len = strtol( s + 1, &s, 10 );
  538. if (*s != '}')
  539. goto bail;
  540. s = cur->val = nfmalloc( cur->len );
  541. /* dump whats left over in the input buffer */
  542. n = imap->buf.bytes - imap->buf.offset;
  543. if (n > bytes)
  544. /* the entire message fit in the buffer */
  545. n = bytes;
  546. memcpy( s, imap->buf.buf + imap->buf.offset, n );
  547. s += n;
  548. bytes -= n;
  549. /* mark that we used part of the buffer */
  550. imap->buf.offset += n;
  551. /* now read the rest of the message */
  552. while (bytes > 0) {
  553. if ((n = socket_read (&imap->buf.sock, s, bytes)) <= 0)
  554. goto bail;
  555. s += n;
  556. bytes -= n;
  557. }
  558. if (buffer_gets( &imap->buf, &s ))
  559. goto bail;
  560. } else if (*s == '"') {
  561. /* quoted string */
  562. s++;
  563. p = s;
  564. for (; *s != '"'; s++)
  565. if (!*s)
  566. goto bail;
  567. cur->len = s - p;
  568. s++;
  569. cur->val = nfmalloc( cur->len + 1 );
  570. memcpy( cur->val, p, cur->len );
  571. cur->val[cur->len] = 0;
  572. } else {
  573. /* atom */
  574. p = s;
  575. for (; *s && !isspace( (unsigned char)*s ); s++)
  576. if (level && *s == ')')
  577. break;
  578. cur->len = s - p;
  579. if (cur->len == 3 && !memcmp ("NIL", p, 3))
  580. cur->val = NIL;
  581. else {
  582. cur->val = nfmalloc( cur->len + 1 );
  583. memcpy( cur->val, p, cur->len );
  584. cur->val[cur->len] = 0;
  585. }
  586. }
  587. if (!level)
  588. break;
  589. if (!*s)
  590. goto bail;
  591. }
  592. *sp = s;
  593. *curp = 0;
  594. return 0;
  595. bail:
  596. *curp = 0;
  597. return -1;
  598. }
  599. static list_t *
  600. parse_imap_list( imap_t *imap, char **sp )
  601. {
  602. list_t *head;
  603. if (!parse_imap_list_l( imap, sp, &head, 0 ))
  604. return head;
  605. free_list( head );
  606. return NULL;
  607. }
  608. static list_t *
  609. parse_list( char **sp )
  610. {
  611. return parse_imap_list( 0, sp );
  612. }
  613. static int
  614. parse_fetch( imap_t *imap, char *cmd ) /* move this down */
  615. {
  616. list_t *tmp, *list, *flags;
  617. char *body = 0;
  618. imap_message_t *cur;
  619. msg_data_t *msgdata;
  620. struct imap_cmd *cmdp;
  621. int uid = 0, mask = 0, status = 0, size = 0;
  622. unsigned i;
  623. list = parse_imap_list( imap, &cmd );
  624. if (!is_list( list )) {
  625. fprintf( stderr, "IMAP error: bogus FETCH response\n" );
  626. free_list( list );
  627. return -1;
  628. }
  629. for (tmp = list->child; tmp; tmp = tmp->next) {
  630. if (is_atom( tmp )) {
  631. if (!strcmp( "UID", tmp->val )) {
  632. tmp = tmp->next;
  633. if (is_atom( tmp ))
  634. uid = atoi( tmp->val );
  635. else
  636. fprintf( stderr, "IMAP error: unable to parse UID\n" );
  637. } else if (!strcmp( "FLAGS", tmp->val )) {
  638. tmp = tmp->next;
  639. if (is_list( tmp )) {
  640. for (flags = tmp->child; flags; flags = flags->next) {
  641. if (is_atom( flags )) {
  642. if (!strcmp( "\\Recent", flags->val )) {
  643. status |= M_RECENT;
  644. goto flagok;
  645. }
  646. for (i = 0; i < as(Flags); i++)
  647. if (!strcmp( Flags[i], flags->val )) {
  648. mask |= 1 << i;
  649. goto flagok;
  650. }
  651. fprintf( stderr, "IMAP warning: unknown flag %s\n", flags->val );
  652. flagok: ;
  653. } else
  654. fprintf( stderr, "IMAP error: unable to parse FLAGS list\n" );
  655. }
  656. status |= M_FLAGS;
  657. } else
  658. fprintf( stderr, "IMAP error: unable to parse FLAGS\n" );
  659. } else if (!strcmp( "RFC822.SIZE", tmp->val )) {
  660. tmp = tmp->next;
  661. if (is_atom( tmp ))
  662. size = atoi( tmp->val );
  663. else
  664. fprintf( stderr, "IMAP error: unable to parse SIZE\n" );
  665. } else if (!strcmp( "BODY[]", tmp->val )) {
  666. tmp = tmp->next;
  667. if (is_atom( tmp )) {
  668. body = tmp->val;
  669. tmp->val = 0; /* don't free together with list */
  670. size = tmp->len;
  671. } else
  672. fprintf( stderr, "IMAP error: unable to parse BODY[]\n" );
  673. }
  674. }
  675. }
  676. if (body) {
  677. for (cmdp = imap->in_progress; cmdp; cmdp = cmdp->next)
  678. if (cmdp->cb.uid == uid)
  679. goto gotuid;
  680. fprintf( stderr, "IMAP error: unexpected FETCH response (UID %d)\n", uid );
  681. free_list( list );
  682. return -1;
  683. gotuid:
  684. msgdata = (msg_data_t *)cmdp->cb.ctx;
  685. msgdata->data = body;
  686. msgdata->len = size;
  687. msgdata->crlf = 1;
  688. if (status & M_FLAGS)
  689. msgdata->flags = mask;
  690. } else if (uid) { /* ignore async flag updates for now */
  691. /* XXX this will need sorting for out-of-order (multiple queries) */
  692. cur = nfcalloc( sizeof(*cur) );
  693. *imap->msgapp = &cur->gen;
  694. imap->msgapp = &cur->gen.next;
  695. cur->gen.next = 0;
  696. cur->gen.uid = uid;
  697. cur->gen.flags = mask;
  698. cur->gen.status = status;
  699. cur->gen.size = size;
  700. }
  701. free_list( list );
  702. return 0;
  703. }
  704. static void
  705. parse_capability( imap_t *imap, char *cmd )
  706. {
  707. char *arg;
  708. unsigned i;
  709. imap->caps = 0x80000000;
  710. while ((arg = next_arg( &cmd )))
  711. for (i = 0; i < as(cap_list); i++)
  712. if (!strcmp( cap_list[i], arg ))
  713. imap->caps |= 1 << i;
  714. imap->rcaps = imap->caps;
  715. }
  716. static int
  717. parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s )
  718. {
  719. imap_t *imap = ctx->imap;
  720. char *arg, *p;
  721. if (*s != '[')
  722. return RESP_OK; /* no response code */
  723. s++;
  724. if (!(p = strchr( s, ']' ))) {
  725. fprintf( stderr, "IMAP error: malformed response code\n" );
  726. return RESP_BAD;
  727. }
  728. *p++ = 0;
  729. arg = next_arg( &s );
  730. if (!strcmp( "UIDVALIDITY", arg )) {
  731. if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg ))) {
  732. fprintf( stderr, "IMAP error: malformed UIDVALIDITY status\n" );
  733. return RESP_BAD;
  734. }
  735. } else if (!strcmp( "UIDNEXT", arg )) {
  736. if (!(arg = next_arg( &s )) || !(imap->uidnext = atoi( arg ))) {
  737. fprintf( stderr, "IMAP error: malformed NEXTUID status\n" );
  738. return RESP_BAD;
  739. }
  740. } else if (!strcmp( "CAPABILITY", arg )) {
  741. parse_capability( imap, s );
  742. } else if (!strcmp( "ALERT", arg )) {
  743. /* RFC2060 says that these messages MUST be displayed
  744. * to the user
  745. */
  746. for (; isspace( (unsigned char)*p ); p++);
  747. fprintf( stderr, "*** IMAP ALERT *** %s\n", p );
  748. } else if (cb && cb->ctx && !strcmp( "APPENDUID", arg )) {
  749. if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg )) ||
  750. !(arg = next_arg( &s )) || !(*(int *)cb->ctx = atoi( arg )))
  751. {
  752. fprintf( stderr, "IMAP error: malformed APPENDUID status\n" );
  753. return RESP_BAD;
  754. }
  755. }
  756. return RESP_OK;
  757. }
  758. static void
  759. parse_search( imap_t *imap, char *cmd )
  760. {
  761. char *arg;
  762. struct imap_cmd *cmdp;
  763. int uid;
  764. arg = next_arg( &cmd );
  765. if (!arg || !(uid = atoi( arg ))) {
  766. fprintf( stderr, "IMAP error: malformed SEARCH response\n" );
  767. return;
  768. }
  769. /* Find the first command that expects a UID - this is guaranteed
  770. * to come in-order, as there are no other means to identify which
  771. * SEARCH response belongs to which request.
  772. */
  773. for (cmdp = imap->in_progress; cmdp; cmdp = cmdp->next)
  774. if (cmdp->cb.uid == -1) {
  775. *(int *)cmdp->cb.ctx = uid;
  776. return;
  777. }
  778. fprintf( stderr, "IMAP error: unexpected SEARCH response (UID %u)\n", uid );
  779. }
  780. static void
  781. parse_list_rsp( imap_store_t *ctx, char *cmd )
  782. {
  783. imap_t *imap = ctx->imap;
  784. char *arg;
  785. list_t *list, *lp;
  786. int l;
  787. list = parse_list( &cmd );
  788. if (list->val == LIST)
  789. for (lp = list->child; lp; lp = lp->next)
  790. if (is_atom( lp ) && !strcasecmp( lp->val, "\\NoSelect" )) {
  791. free_list( list );
  792. return;
  793. }
  794. free_list( list );
  795. (void) next_arg( &cmd ); /* skip delimiter */
  796. arg = next_arg( &cmd );
  797. l = strlen( ctx->gen.conf->path );
  798. if (memcmp( arg, ctx->gen.conf->path, l ))
  799. return;
  800. arg += l;
  801. if (!memcmp( arg + strlen( arg ) - 5, ".lock", 5 )) /* workaround broken servers */
  802. return;
  803. add_string_list( &imap->boxes, arg );
  804. }
  805. static int
  806. get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
  807. {
  808. imap_t *imap = ctx->imap;
  809. struct imap_cmd *cmdp, **pcmdp, *ncmdp;
  810. char *cmd, *arg, *arg1, *p;
  811. int n, resp, resp2, tag;
  812. for (;;) {
  813. if (buffer_gets( &imap->buf, &cmd ))
  814. return RESP_BAD;
  815. arg = next_arg( &cmd );
  816. if (*arg == '*') {
  817. arg = next_arg( &cmd );
  818. if (!arg) {
  819. fprintf( stderr, "IMAP error: unable to parse untagged response\n" );
  820. return RESP_BAD;
  821. }
  822. if (!strcmp( "NAMESPACE", arg )) {
  823. imap->ns_personal = parse_list( &cmd );
  824. imap->ns_other = parse_list( &cmd );
  825. imap->ns_shared = parse_list( &cmd );
  826. } else if (!strcmp( "OK", arg ) || !strcmp( "BAD", arg ) ||
  827. !strcmp( "NO", arg ) || !strcmp( "BYE", arg )) {
  828. if ((resp = parse_response_code( ctx, 0, cmd )) != RESP_OK)
  829. return resp;
  830. } else if (!strcmp( "CAPABILITY", arg ))
  831. parse_capability( imap, cmd );
  832. else if (!strcmp( "LIST", arg ))
  833. parse_list_rsp( ctx, cmd );
  834. else if (!strcmp( "SEARCH", arg ))
  835. parse_search( imap, cmd );
  836. else if ((arg1 = next_arg( &cmd ))) {
  837. if (!strcmp( "EXISTS", arg1 ))
  838. ctx->gen.count = atoi( arg );
  839. else if (!strcmp( "RECENT", arg1 ))
  840. ctx->gen.recent = atoi( arg );
  841. else if(!strcmp ( "FETCH", arg1 )) {
  842. if (parse_fetch( imap, cmd ))
  843. return RESP_BAD;
  844. }
  845. } else {
  846. fprintf( stderr, "IMAP error: unable to parse untagged response\n" );
  847. return RESP_BAD;
  848. }
  849. } else if (!imap->in_progress) {
  850. fprintf( stderr, "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" );
  851. return RESP_BAD;
  852. } else if (*arg == '+') {
  853. /* This can happen only with the last command underway, as
  854. it enforces a round-trip. */
  855. cmdp = (struct imap_cmd *)((char *)imap->in_progress_append -
  856. offsetof(struct imap_cmd, next));
  857. if (cmdp->cb.data) {
  858. n = socket_write( &imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen );
  859. free( cmdp->cb.data );
  860. cmdp->cb.data = 0;
  861. if (n != (int)cmdp->cb.dlen)
  862. return RESP_BAD;
  863. } else if (cmdp->cb.cont) {
  864. if (cmdp->cb.cont( ctx, cmdp, cmd ))
  865. return RESP_BAD;
  866. } else {
  867. fprintf( stderr, "IMAP error: unexpected command continuation request\n" );
  868. return RESP_BAD;
  869. }
  870. if (socket_write( &imap->buf.sock, "\r\n", 2 ) != 2)
  871. return RESP_BAD;
  872. if (!cmdp->cb.cont)
  873. imap->literal_pending = 0;
  874. if (!tcmd)
  875. return DRV_OK;
  876. } else {
  877. tag = atoi( arg );
  878. for (pcmdp = &imap->in_progress; (cmdp = *pcmdp); pcmdp = &cmdp->next)
  879. if (cmdp->tag == tag)
  880. goto gottag;
  881. fprintf( stderr, "IMAP error: unexpected tag %s\n", arg );
  882. return RESP_BAD;
  883. gottag:
  884. if (!(*pcmdp = cmdp->next))
  885. imap->in_progress_append = pcmdp;
  886. imap->num_in_progress--;
  887. if (cmdp->cb.cont || cmdp->cb.data)
  888. imap->literal_pending = 0;
  889. arg = next_arg( &cmd );
  890. if (!strcmp( "OK", arg ))
  891. resp = DRV_OK;
  892. else {
  893. if (!strcmp( "NO", arg )) {
  894. if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT, APPEND or UID COPY */
  895. p = strchr( cmdp->cmd, '"' );
  896. if (!issue_imap_cmd( ctx, 0, "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p )) {
  897. resp = RESP_BAD;
  898. goto normal;
  899. }
  900. /* not waiting here violates the spec, but a server that does not
  901. grok this nonetheless violates it too. */
  902. cmdp->cb.create = 0;
  903. if (!(ncmdp = issue_imap_cmd( ctx, &cmdp->cb, "%s", cmdp->cmd ))) {
  904. resp = RESP_BAD;
  905. goto normal;
  906. }
  907. free( cmdp->cmd );
  908. free( cmdp );
  909. if (!tcmd)
  910. return 0; /* ignored */
  911. if (cmdp == tcmd)
  912. tcmd = ncmdp;
  913. continue;
  914. }
  915. resp = RESP_NO;
  916. } else /*if (!strcmp( "BAD", arg ))*/
  917. resp = RESP_BAD;
  918. fprintf( stderr, "IMAP command '%s' returned an error: %s %s\n",
  919. memcmp (cmdp->cmd, "LOGIN", 5) ?
  920. cmdp->cmd : "LOGIN <user> <pass>",
  921. arg, cmd ? cmd : "");
  922. }
  923. if ((resp2 = parse_response_code( ctx, &cmdp->cb, cmd )) > resp)
  924. resp = resp2;
  925. normal:
  926. if (cmdp->cb.done)
  927. cmdp->cb.done( ctx, cmdp, resp );
  928. if (cmdp->cb.data)
  929. free( cmdp->cb.data );
  930. free( cmdp->cmd );
  931. free( cmdp );
  932. if (!tcmd || tcmd == cmdp)
  933. return resp;
  934. }
  935. }
  936. /* not reached */
  937. }
  938. static void
  939. imap_close_server( imap_store_t *ictx )
  940. {
  941. imap_t *imap = ictx->imap;
  942. if (imap->buf.sock.fd != -1) {
  943. imap_exec( ictx, 0, "LOGOUT" );
  944. close( imap->buf.sock.fd );
  945. }
  946. #ifdef HAVE_LIBSSL
  947. if (imap->SSLContext)
  948. SSL_CTX_free( imap->SSLContext );
  949. #endif
  950. free_list( imap->ns_personal );
  951. free_list( imap->ns_other );
  952. free_list( imap->ns_shared );
  953. free( imap );
  954. }
  955. static void
  956. imap_close_store( store_t *ctx )
  957. {
  958. imap_close_server( (imap_store_t *)ctx );
  959. free_generic_messages( ctx->msgs );
  960. free( ctx );
  961. }
  962. #ifdef HAVE_LIBSSL
  963. static int
  964. start_tls( imap_store_t *ctx )
  965. {
  966. imap_t *imap = ctx->imap;
  967. int ret;
  968. static int ssl_inited;
  969. if (!ssl_inited) {
  970. SSL_library_init();
  971. SSL_load_error_strings();
  972. ssl_inited = 1;
  973. }
  974. if (init_ssl_ctx( ctx ))
  975. return 1;
  976. imap->buf.sock.ssl = SSL_new( imap->SSLContext );
  977. SSL_set_fd( imap->buf.sock.ssl, imap->buf.sock.fd );
  978. if ((ret = SSL_connect( imap->buf.sock.ssl )) <= 0) {
  979. socket_perror( "connect", &imap->buf.sock, ret );
  980. return 1;
  981. }
  982. /* verify the server certificate */
  983. if (verify_cert( imap->buf.sock.ssl ))
  984. return 1;
  985. imap->buf.sock.use_ssl = 1;
  986. info( "Connection is now encrypted\n" );
  987. return 0;
  988. }
  989. #define ENCODED_SIZE(n) (4*((n+2)/3))
  990. static char
  991. hexchar( unsigned int b )
  992. {
  993. if (b < 10)
  994. return '0' + b;
  995. return 'a' + (b - 10);
  996. }
  997. /* XXX merge into do_cram_auth? */
  998. static char *
  999. cram( const char *challenge, const char *user, const char *pass )
  1000. {
  1001. HMAC_CTX hmac;
  1002. char hash[16];
  1003. char hex[33];
  1004. int i;
  1005. unsigned int hashlen = sizeof(hash);
  1006. char buf[256];
  1007. int len = strlen( challenge );
  1008. char *response = nfcalloc( 1 + len );
  1009. char *final;
  1010. /* response will always be smaller than challenge because we are
  1011. * decoding.
  1012. */
  1013. len = EVP_DecodeBlock( (unsigned char *)response, (unsigned char *)challenge, strlen( challenge ) );
  1014. HMAC_Init( &hmac, (unsigned char *) pass, strlen( pass ), EVP_md5() );
  1015. HMAC_Update( &hmac, (unsigned char *)response, strlen( response ) );
  1016. HMAC_Final( &hmac, (unsigned char *)hash, &hashlen );
  1017. assert( hashlen == sizeof(hash) );
  1018. free( response );
  1019. hex[32] = 0;
  1020. for (i = 0; i < 16; i++) {
  1021. hex[2 * i] = hexchar( (hash[i] >> 4) & 0xf );
  1022. hex[2 * i + 1] = hexchar( hash[i] & 0xf );
  1023. }
  1024. nfsnprintf( buf, sizeof(buf), "%s %s", user, hex );
  1025. len = strlen( buf );
  1026. len = ENCODED_SIZE( len ) + 1;
  1027. final = nfmalloc( len );
  1028. final[len - 1] = 0;
  1029. assert( EVP_EncodeBlock( (unsigned char *)final, (unsigned char *)buf, strlen( buf ) ) == len - 1 );
  1030. return final;
  1031. }
  1032. static int
  1033. do_cram_auth (imap_store_t *ctx, struct imap_cmd *cmdp, const char *prompt)
  1034. {
  1035. imap_t *imap = ctx->imap;
  1036. imap_server_conf_t *srvc = ((imap_store_conf_t *)ctx->gen.conf)->server;
  1037. char *resp;
  1038. int n, l;
  1039. resp = cram( prompt, srvc->user, srvc->pass );
  1040. if (Verbose)
  1041. printf( ">+> %s\n", resp );
  1042. l = strlen( resp );
  1043. n = socket_write( &imap->buf.sock, resp, l );
  1044. free( resp );
  1045. if (n != l)
  1046. return -1;
  1047. cmdp->cb.cont = 0;
  1048. return 0;
  1049. }
  1050. #endif
  1051. static store_t *
  1052. imap_open_store( store_conf_t *conf, store_t *oldctx )
  1053. {
  1054. imap_store_conf_t *cfg = (imap_store_conf_t *)conf;
  1055. imap_server_conf_t *srvc = cfg->server;
  1056. imap_store_t *ctx = (imap_store_t *)oldctx;
  1057. imap_t *imap;
  1058. char *arg, *rsp;
  1059. struct hostent *he;
  1060. struct sockaddr_in addr;
  1061. int s, a[2], preauth;
  1062. #if HAVE_LIBSSL
  1063. int use_ssl;
  1064. #endif
  1065. if (ctx) {
  1066. if (((imap_store_conf_t *)(ctx->gen.conf))->server == cfg->server) {
  1067. ctx->gen.conf = conf;
  1068. imap = ctx->imap;
  1069. goto final;
  1070. }
  1071. imap_close_server( ctx );
  1072. } else
  1073. ctx = nfcalloc( sizeof(*ctx) );
  1074. ctx->gen.conf = conf;
  1075. ctx->imap = imap = nfcalloc( sizeof(*imap) );
  1076. imap->buf.sock.fd = -1;
  1077. imap->in_progress_append = &imap->in_progress;
  1078. /* open connection to IMAP server */
  1079. #if HAVE_LIBSSL
  1080. use_ssl = 0;
  1081. #endif
  1082. if (srvc->tunnel) {
  1083. info( "Starting tunnel '%s'... ", srvc->tunnel );
  1084. if (socketpair( PF_UNIX, SOCK_STREAM, 0, a )) {
  1085. perror( "socketpair" );
  1086. exit( 1 );
  1087. }
  1088. if (fork() == 0) {
  1089. if (dup2( a[0], 0 ) == -1 || dup2( a[0], 1 ) == -1)
  1090. _exit( 127 );
  1091. close( a[0] );
  1092. close( a[1] );
  1093. execl( "/bin/sh", "sh", "-c", srvc->tunnel, 0 );
  1094. _exit( 127 );
  1095. }
  1096. close (a[0]);
  1097. imap->buf.sock.fd = a[1];
  1098. info( "ok\n" );
  1099. } else {
  1100. memset( &addr, 0, sizeof(addr) );
  1101. addr.sin_port = htons( srvc->port );
  1102. addr.sin_family = AF_INET;
  1103. info( "Resolving %s... ", srvc->host );
  1104. he = gethostbyname( srvc->host );
  1105. if (!he) {
  1106. perror( "gethostbyname" );
  1107. goto bail;
  1108. }
  1109. info( "ok\n" );
  1110. addr.sin_addr.s_addr = *((int *) he->h_addr_list[0]);
  1111. s = socket( PF_INET, SOCK_STREAM, 0 );
  1112. info( "Connecting to %s:%hu... ", inet_ntoa( addr.sin_addr ), ntohs( addr.sin_port ) );
  1113. if (connect( s, (struct sockaddr *)&addr, sizeof(addr) )) {
  1114. close( s );
  1115. perror( "connect" );
  1116. goto bail;
  1117. }
  1118. info( "ok\n" );
  1119. imap->buf.sock.fd = s;
  1120. #if HAVE_LIBSSL
  1121. if (srvc->use_imaps) {
  1122. if (start_tls( ctx ))
  1123. goto bail;
  1124. use_ssl = 1;
  1125. }
  1126. #endif
  1127. }
  1128. /* read the greeting string */
  1129. if (buffer_gets( &imap->buf, &rsp )) {
  1130. fprintf( stderr, "IMAP error: no greeting response\n" );
  1131. goto bail;
  1132. }
  1133. arg = next_arg( &rsp );
  1134. if (!arg || *arg != '*' || (arg = next_arg( &rsp )) == NULL) {
  1135. fprintf( stderr, "IMAP error: invalid greeting response\n" );
  1136. goto bail;
  1137. }
  1138. preauth = 0;
  1139. if (!strcmp( "PREAUTH", arg ))
  1140. preauth = 1;
  1141. else if (strcmp( "OK", arg ) != 0) {
  1142. fprintf( stderr, "IMAP error: unknown greeting response\n" );
  1143. goto bail;
  1144. }
  1145. parse_response_code( ctx, 0, rsp );
  1146. if (!imap->caps && imap_exec( ctx, 0, "CAPABILITY" ) != RESP_OK)
  1147. goto bail;
  1148. if (!preauth) {
  1149. #if HAVE_LIBSSL
  1150. if (!srvc->use_imaps && (srvc->use_sslv2 || srvc->use_sslv3 || srvc->use_tlsv1)) {
  1151. /* always try to select SSL support if available */
  1152. if (CAP(STARTTLS)) {
  1153. if (imap_exec( ctx, 0, "STARTTLS" ) != RESP_OK)
  1154. goto bail;
  1155. if (start_tls( ctx ))
  1156. goto bail;
  1157. use_ssl = 1;
  1158. if (imap_exec( ctx, 0, "CAPABILITY" ) != RESP_OK)
  1159. goto bail;
  1160. } else {
  1161. if (srvc->require_ssl) {
  1162. fprintf( stderr, "IMAP error: SSL support not available\n" );
  1163. goto bail;
  1164. } else
  1165. warn( "IMAP warning: SSL support not available\n" );
  1166. }
  1167. }
  1168. #endif
  1169. info ("Logging in...\n");
  1170. if (!srvc->user) {
  1171. fprintf( stderr, "Skipping server %s, no user\n", srvc->host );
  1172. goto bail;
  1173. }
  1174. if (!srvc->pass) {
  1175. char prompt[80];
  1176. sprintf( prompt, "Password (%s@%s): ", srvc->user, srvc->host );
  1177. arg = getpass( prompt );
  1178. if (!arg) {
  1179. perror( "getpass" );
  1180. exit( 1 );
  1181. }
  1182. if (!*arg) {
  1183. fprintf( stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host );
  1184. goto bail;
  1185. }
  1186. /*
  1187. * getpass() returns a pointer to a static buffer. make a copy
  1188. * for long term storage.
  1189. */
  1190. srvc->pass = nfstrdup( arg );
  1191. }
  1192. #if HAVE_LIBSSL
  1193. if (CAP(CRAM)) {
  1194. struct imap_cmd_cb cb;
  1195. info( "Authenticating with CRAM-MD5\n" );
  1196. memset( &cb, 0, sizeof(cb) );
  1197. cb.cont = do_cram_auth;
  1198. if (imap_exec( ctx, &cb, "AUTHENTICATE CRAM-MD5" ) != RESP_OK)
  1199. goto bail;
  1200. } else if (srvc->require_cram) {
  1201. fprintf( stderr, "IMAP error: CRAM-MD5 authentication is not supported by server\n" );
  1202. goto bail;
  1203. } else
  1204. #endif
  1205. {
  1206. if (CAP(NOLOGIN)) {
  1207. fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host );
  1208. goto bail;
  1209. }
  1210. #if HAVE_LIBSSL
  1211. if (!use_ssl)
  1212. #endif
  1213. warn( "*** IMAP Warning *** Password is being sent in the clear\n" );
  1214. if (imap_exec( ctx, 0, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass ) != RESP_OK) {
  1215. fprintf( stderr, "IMAP error: LOGIN failed\n" );
  1216. goto bail;
  1217. }
  1218. }
  1219. } /* !preauth */
  1220. final:
  1221. ctx->prefix = "";
  1222. if (*conf->path)
  1223. ctx->prefix = conf->path;
  1224. else if (cfg->use_namespace && CAP(NAMESPACE)) {
  1225. /* get NAMESPACE info */
  1226. if (imap_exec( ctx, 0, "NAMESPACE" ) != RESP_OK)
  1227. goto bail;
  1228. /* XXX for now assume personal namespace */
  1229. if (is_list( imap->ns_personal ) &&
  1230. is_list( imap->ns_personal->child ) &&
  1231. is_atom( imap->ns_personal->child->child ))
  1232. ctx->prefix = imap->ns_personal->child->child->val;
  1233. }
  1234. ctx->trashnc = 1;
  1235. return (store_t *)ctx;
  1236. bail:
  1237. imap_close_store( &ctx->gen );
  1238. return 0;
  1239. }
  1240. static void
  1241. imap_prepare( store_t *gctx, int opts )
  1242. {
  1243. free_generic_messages( gctx->msgs );
  1244. gctx->msgs = 0;
  1245. gctx->opts = opts;
  1246. }
  1247. static int
  1248. imap_select( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs )
  1249. {
  1250. imap_store_t *ctx = (imap_store_t *)gctx;
  1251. imap_t *imap = ctx->imap;
  1252. const char *prefix;
  1253. int ret, i, j, bl;
  1254. struct imap_cmd_cb cb;
  1255. char buf[1000];
  1256. if (!strcmp( gctx->name, "INBOX" )) {
  1257. // imap->currentnc = 0;
  1258. prefix = "";
  1259. } else {
  1260. // imap->currentnc = 1; /* could use LIST results for that */
  1261. prefix = ctx->prefix;
  1262. }
  1263. memset( &cb, 0, sizeof(cb) );
  1264. cb.create = (gctx->opts & OPEN_CREATE) != 0;
  1265. cb.trycreate = 1;
  1266. if ((ret = imap_exec_b( ctx, &cb, "SELECT \"%s%s\"", prefix, gctx->name )) != DRV_OK)
  1267. goto bail;
  1268. if (gctx->count) {
  1269. imap->msgapp = &gctx->msgs;
  1270. sort_ints( excs, nexcs );
  1271. for (i = 0; i < nexcs; ) {
  1272. for (bl = 0; i < nexcs && bl < 960; i++) {
  1273. if (bl)
  1274. buf[bl++] = ',';
  1275. bl += sprintf( buf + bl, "%d", excs[i] );
  1276. j = i;
  1277. for (; i + 1 < nexcs && excs[i + 1] == excs[i] + 1; i++);
  1278. if (i != j)
  1279. bl += sprintf( buf + bl, ":%d", excs[i] );
  1280. }
  1281. if ((ret = imap_exec_b( ctx, 0, "UID FETCH %s (UID%s%s)", buf,
  1282. (gctx->opts & OPEN_FLAGS) ? " FLAGS" : "",
  1283. (gctx->opts & OPEN_SIZE) ? " RFC822.SIZE" : "" )) != DRV_OK)
  1284. goto bail;
  1285. }
  1286. if (maxuid == INT_MAX)
  1287. maxuid = imap->uidnext ? imap->uidnext - 1 : 1000000000;
  1288. if (maxuid >= minuid &&
  1289. (ret = imap_exec_b( ctx, 0, "UID FETCH %d:%d (UID%s%s)", minuid, maxuid,
  1290. (gctx->opts & OPEN_FLAGS) ? " FLAGS" : "",
  1291. (gctx->opts & OPEN_SIZE) ? " RFC822.SIZE" : "" )) != DRV_OK)
  1292. goto bail;
  1293. }
  1294. ret = DRV_OK;
  1295. bail:
  1296. if (excs)
  1297. free( excs );
  1298. return ret;
  1299. }
  1300. static int
  1301. imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data )
  1302. {
  1303. struct imap_cmd_cb cb;
  1304. memset( &cb, 0, sizeof(cb) );
  1305. cb.uid = msg->uid;
  1306. cb.ctx = data;
  1307. return imap_exec_m( (imap_store_t *)ctx, &cb, "UID FETCH %d (%sBODY.PEEK[])",
  1308. msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " );
  1309. }
  1310. static int
  1311. imap_make_flags( int flags, char *buf )
  1312. {
  1313. const char *s;
  1314. unsigned i, d;
  1315. for (i = d = 0; i < as(Flags); i++)
  1316. if (flags & (1 << i)) {
  1317. buf[d++] = ' ';
  1318. for (s = Flags[i]; *s; s++)
  1319. buf[d++] = *s;
  1320. }
  1321. buf[0] = '(';
  1322. buf[d++] = ')';
  1323. return d;
  1324. }
  1325. static int
  1326. imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags)
  1327. {
  1328. char buf[256];
  1329. buf[imap_make_flags( flags, buf )] = 0;
  1330. return issue_imap_cmd_w( ctx, 0, "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf ) ? DRV_OK : DRV_STORE_BAD;
  1331. }
  1332. static int
  1333. imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del )
  1334. {
  1335. imap_store_t *ctx = (imap_store_t *)gctx;
  1336. int ret;
  1337. if (msg) {
  1338. uid = msg->uid;
  1339. add &= ~msg->flags;
  1340. del &= msg->flags;
  1341. msg->flags |= add;
  1342. msg->flags &= ~del;
  1343. }
  1344. if ((!add || (ret = imap_flags_helper( ctx, uid, '+', add )) == DRV_OK) &&
  1345. (!del || (ret = imap_flags_helper( ctx, uid, '-', del )) == DRV_OK))
  1346. return DRV_OK;
  1347. return ret;
  1348. }
  1349. static int
  1350. imap_close( store_t *ctx )
  1351. {
  1352. return imap_exec_b( (imap_store_t *)ctx, 0, "CLOSE" );
  1353. }
  1354. static int
  1355. imap_trash_msg( store_t *gctx, message_t *msg )
  1356. {
  1357. imap_store_t *ctx = (imap_store_t *)gctx;
  1358. struct imap_cmd_cb cb;
  1359. memset( &cb, 0, sizeof(cb) );
  1360. cb.create = 1;
  1361. return imap_exec_m( ctx, &cb, "UID COPY %d \"%s%s\"",
  1362. msg->uid, ctx->prefix, gctx->conf->trash );
  1363. }
  1364. #define TUIDL 8
  1365. static int
  1366. imap_store_msg( store_t *gctx, msg_data_t *data, int *uid )
  1367. {
  1368. imap_store_t *ctx = (imap_store_t *)gctx;
  1369. imap_t *imap = ctx->imap;
  1370. struct imap_cmd_cb cb;
  1371. char *fmap, *buf;
  1372. const char *prefix, *box;
  1373. int ret, i, j, d, len, extra, nocr;
  1374. int start, sbreak = 0, ebreak = 0;
  1375. char flagstr[128], tuid[TUIDL * 2 + 1];
  1376. memset( &cb, 0, sizeof(cb) );
  1377. fmap = data->data;
  1378. len = data->len;
  1379. nocr = !data->crlf;
  1380. extra = 0, i = 0;
  1381. if (!CAP(UIDPLUS) && uid) {
  1382. nloop:
  1383. start = i;
  1384. while (i < len)
  1385. if (fmap[i++] == '\n') {
  1386. extra += nocr;
  1387. if (i - 2 + nocr == start) {
  1388. sbreak = ebreak = i - 2 + nocr;
  1389. goto mktid;
  1390. }
  1391. if (!memcmp( fmap + start, "X-TUID: ", 8 )) {
  1392. extra -= (ebreak = i) - (sbreak = start) + nocr;
  1393. goto mktid;
  1394. }
  1395. goto nloop;
  1396. }
  1397. /* invalid message */
  1398. free( fmap );
  1399. return DRV_MSG_BAD;
  1400. mktid:
  1401. for (j = 0; j < TUIDL; j++)
  1402. sprintf( tuid + j * 2, "%02x", arc4_getbyte() );
  1403. extra += 8 + TUIDL * 2 + 2;
  1404. }
  1405. if (nocr)
  1406. for (; i < len; i++)
  1407. if (fmap[i] == '\n')
  1408. extra++;
  1409. cb.dlen = len + extra;
  1410. buf = cb.data = nfmalloc( cb.dlen );
  1411. i = 0;
  1412. if (!CAP(UIDPLUS) && uid) {
  1413. if (nocr) {
  1414. for (; i < sbreak; i++)
  1415. if (fmap[i] == '\n') {
  1416. *buf++ = '\r';
  1417. *buf++ = '\n';
  1418. } else
  1419. *buf++ = fmap[i];
  1420. } else {
  1421. memcpy( buf, fmap, sbreak );
  1422. buf += sbreak;
  1423. }
  1424. memcpy( buf, "X-TUID: ", 8 );
  1425. buf += 8;
  1426. memcpy( buf, tuid, TUIDL * 2 );
  1427. buf += TUIDL * 2;
  1428. *buf++ = '\r';
  1429. *buf++ = '\n';
  1430. i = ebreak;
  1431. }
  1432. if (nocr) {
  1433. for (; i < len; i++)
  1434. if (fmap[i] == '\n') {
  1435. *buf++ = '\r';
  1436. *buf++ = '\n';
  1437. } else
  1438. *buf++ = fmap[i];
  1439. } else
  1440. memcpy( buf, fmap + i, len - i );
  1441. free( fmap );
  1442. d = 0;
  1443. if (data->flags) {
  1444. d = imap_make_flags( data->flags, flagstr );
  1445. flagstr[d++] = ' ';
  1446. }
  1447. flagstr[d] = 0;
  1448. if (!uid) {
  1449. box = gctx->conf->trash;
  1450. prefix = ctx->prefix;
  1451. cb.create = 1;
  1452. if (ctx->trashnc)
  1453. imap->caps = imap->rcaps & ~(1 << LITERALPLUS);
  1454. } else {
  1455. box = gctx->name;
  1456. prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix;
  1457. cb.create = (gctx->opts & OPEN_CREATE) != 0;
  1458. /*if (ctx->currentnc)
  1459. imap->caps = imap->rcaps & ~(1 << LITERALPLUS);*/
  1460. }
  1461. cb.ctx = uid;
  1462. ret = imap_exec_m( ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr );
  1463. imap->caps = imap->rcaps;
  1464. if (ret != DRV_OK)
  1465. return ret;
  1466. if (!uid)
  1467. ctx->trashnc = 0;
  1468. else {
  1469. /*ctx->currentnc = 0;*/
  1470. gctx->count++;
  1471. }
  1472. if (CAP(UIDPLUS) || !uid)
  1473. return DRV_OK;
  1474. /* Didn't receive an APPENDUID */
  1475. cb.uid = -1; /* we're looking for a UID */
  1476. cb.data = 0; /* reset; ctx still set */
  1477. return imap_exec_m( ctx, &cb, "UID SEARCH HEADER X-TUID %s", tuid );
  1478. }
  1479. static int
  1480. imap_list( store_t *gctx, string_list_t **retb )
  1481. {
  1482. imap_store_t *ctx = (imap_store_t *)gctx;
  1483. imap_t *imap = ctx->imap;
  1484. int ret;
  1485. imap->boxes = 0;
  1486. if ((ret = imap_exec_b( ctx, 0, "LIST \"\" \"%s%%\"", ctx->prefix )) != DRV_OK)
  1487. return ret;
  1488. *retb = imap->boxes;
  1489. return DRV_OK;
  1490. }
  1491. static int
  1492. imap_check( store_t *gctx )
  1493. {
  1494. (void) gctx;
  1495. /* flush queue here */
  1496. return DRV_OK;
  1497. }
  1498. imap_server_conf_t *servers, **serverapp = &servers;
  1499. static int
  1500. imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err )
  1501. {
  1502. imap_store_conf_t *store;
  1503. imap_server_conf_t *server, *srv, sserver;
  1504. if (!strcasecmp( "IMAPAccount", cfg->cmd )) {
  1505. server = nfcalloc( sizeof(*server) );
  1506. server->name = nfstrdup( cfg->val );
  1507. *serverapp = server;
  1508. serverapp = &server->next;
  1509. store = 0;
  1510. } else if (!strcasecmp( "IMAPStore", cfg->cmd )) {
  1511. store = nfcalloc( sizeof(*store) );
  1512. store->gen.driver = &imap_driver;
  1513. store->gen.name = nfstrdup( cfg->val );
  1514. store->use_namespace = 1;
  1515. memset( &sserver, 0, sizeof(sserver) );
  1516. server = &sserver;
  1517. } else
  1518. return 0;
  1519. #if HAVE_LIBSSL
  1520. /* this will probably annoy people, but its the best default just in
  1521. * case people forget to turn it on
  1522. */
  1523. server->require_ssl = 1;
  1524. server->use_tlsv1 = 1;
  1525. #endif
  1526. while (getcline( cfg ) && cfg->cmd) {
  1527. if (!strcasecmp( "Account", cfg->cmd )) {
  1528. for (srv = servers; srv; srv = srv->next)
  1529. if (srv->name && !strcmp( srv->name, cfg->val ))
  1530. goto gotsrv;
  1531. fprintf( stderr, "%s:%d: unknown IMAP account '%s'\n",
  1532. cfg->file, cfg->line, cfg->val );
  1533. *err = 1;
  1534. continue;
  1535. gotsrv:
  1536. store->server = srv;
  1537. } else if (!strcasecmp( "Host", cfg->cmd )) {
  1538. #if HAVE_LIBSSL
  1539. if (!memcmp( "imaps:", cfg->val, 6 )) {
  1540. cfg->val += 6;
  1541. server->use_imaps = 1;
  1542. server->use_sslv2 = 1;
  1543. server->use_sslv3 = 1;
  1544. if (!server->port)
  1545. server->port = 993;
  1546. } else
  1547. #endif
  1548. {
  1549. if (!memcmp( "imap:", cfg->val, 5 ))
  1550. cfg->val += 5;
  1551. if (!server->port)
  1552. server->port = 143;
  1553. }
  1554. if (!memcmp( "//", cfg->val, 2 ))
  1555. cfg->val += 2;
  1556. server->host = nfstrdup( cfg->val );
  1557. }
  1558. else if (!strcasecmp( "User", cfg->cmd ))
  1559. server->user = nfstrdup( cfg->val );
  1560. else if (!strcasecmp( "Pass", cfg->cmd ))
  1561. server->pass = nfstrdup( cfg->val );
  1562. else if (!strcasecmp( "Port", cfg->cmd ))
  1563. server->port = parse_int( cfg );
  1564. #if HAVE_LIBSSL
  1565. else if (!strcasecmp( "CertificateFile", cfg->cmd ))
  1566. server->cert_file = expand_strdup( cfg->val );
  1567. else if (!strcasecmp( "RequireSSL", cfg->cmd ))
  1568. server->require_ssl = parse_bool( cfg );
  1569. else if (!strcasecmp( "UseSSLv2", cfg->cmd ))
  1570. server->use_sslv2 = parse_bool( cfg );
  1571. else if (!strcasecmp( "UseSSLv3", cfg->cmd ))
  1572. server->use_sslv3 = parse_bool( cfg );
  1573. else if (!strcasecmp( "UseTLSv1", cfg->cmd ))
  1574. server->use_tlsv1 = parse_bool( cfg );
  1575. else if (!strcasecmp( "RequireCRAM", cfg->cmd ))
  1576. server->require_cram = parse_bool( cfg );
  1577. #endif
  1578. else if (!strcasecmp( "Tunnel", cfg->cmd ))
  1579. server->tunnel = nfstrdup( cfg->val );
  1580. else if (store) {
  1581. if (!strcasecmp( "UseNamespace", cfg->cmd ))
  1582. store->use_namespace = parse_bool( cfg );
  1583. else if (!strcasecmp( "Path", cfg->cmd ))
  1584. store->gen.path = nfstrdup( cfg->val );
  1585. else
  1586. parse_generic_store( &store->gen, cfg, err );
  1587. } else {
  1588. fprintf( stderr, "%s:%d: unknown keyword '%s'\n",
  1589. cfg->file, cfg->line, cfg->cmd );
  1590. *err = 1;
  1591. }
  1592. }
  1593. if (!store || !store->server) {
  1594. if (!server->tunnel && !server->host) {
  1595. if (store)
  1596. fprintf( stderr, "IMAP store '%s' has incomplete connection details\n", store->gen.name );
  1597. else
  1598. fprintf( stderr, "IMAP account '%s' has incomplete connection details\n", server->name );
  1599. *err = 1;
  1600. /* leaking server/store */
  1601. *storep = 0;
  1602. return 1;
  1603. }
  1604. }
  1605. *storep = &store->gen;
  1606. if (store && !store->server) {
  1607. store->server = nfmalloc( sizeof(sserver) );
  1608. memcpy( store->server, &sserver, sizeof(sserver) );
  1609. }
  1610. return 1;
  1611. }
  1612. struct driver imap_driver = {
  1613. imap_parse_store,
  1614. imap_open_store,
  1615. imap_close_store,
  1616. imap_list,
  1617. imap_prepare,
  1618. imap_select,
  1619. imap_fetch_msg,
  1620. imap_store_msg,
  1621. imap_set_flags,
  1622. imap_trash_msg,
  1623. imap_check,
  1624. imap_close
  1625. };