This source file includes following definitions.
- pop_open
- pop_stat
- pop_list
- pop_retrieve
- pop_retrieve_first
- pop_retrieve_next
- pop_retrieve_flush
- pop_top_first
- pop_top_next
- pop_top_flush
- pop_multi_first
- pop_multi_next
- pop_multi_flush
- pop_delete
- pop_noop
- pop_last
- pop_reset
- pop_quit
- socket_connection
- pop_getline
- sendline
- fullwrite
- getok
- gettermination
- pop_close
- pop_trash
- find_crlf
- load_ws2
- sys_getaddrinfo
- sys_freeaddrinfo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 #include <config.h>
25
26 #ifdef MAIL_USE_POP
27
28 #include <sys/types.h>
29 #ifdef WINDOWSNT
30 #include "ntlib.h"
31 #undef _WIN32_WINNT
32 #define _WIN32_WINNT 0x0501
33 #if defined __MINGW32_VERSION && __MINGW32_VERSION >= 5000002L
34 # include <windows.h>
35 #else
36 # include <winsock2.h>
37 #endif
38 # include <ws2tcpip.h>
39 #undef getaddrinfo
40 #define getaddrinfo sys_getaddrinfo
41 #undef freeaddrinfo
42 #define freeaddrinfo sys_freeaddrinfo
43 int sys_getaddrinfo (const char * node, const char * service,
44 const struct addrinfo * hints, struct addrinfo ** res);
45 void sys_freeaddrinfo (struct addrinfo * ai);
46 #undef SOCKET_ERROR
47 #define RECV(s,buf,len,flags) recv (s,buf,len,flags)
48 #define SEND(s,buf,len,flags) send (s,buf,len,flags)
49 #define CLOSESOCKET(s) closesocket (s)
50 #else
51 #include <netinet/in.h>
52 #include <sys/socket.h>
53 #define RECV(s,buf,len,flags) read (s,buf,len)
54 #define SEND(s,buf,len,flags) write (s,buf,len)
55 #define CLOSESOCKET(s) close (s)
56 #endif
57 #include <pop.h>
58
59 #ifdef HESIOD
60 #include <hesiod.h>
61
62
63
64
65
66
67 extern struct servent *hes_getservbyname ();
68 #endif
69
70 #include <alloca.h>
71 #include <pwd.h>
72 #include <netdb.h>
73 #include <errno.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <unistd.h>
78
79 #ifdef KERBEROS
80 # ifdef HAVE_KRB5_H
81 # include <krb5.h>
82 # endif
83 # ifdef HAVE_KRB_H
84 # include <krb.h>
85 # else
86 # ifdef HAVE_KERBEROSIV_KRB_H
87 # include <kerberosIV/krb.h>
88 # else
89 # ifdef HAVE_KERBEROS_KRB_H
90 # include <kerberos/krb.h>
91 # endif
92 # endif
93 # endif
94 # ifdef HAVE_COM_ERR_H
95 # include <com_err.h>
96 # endif
97 #endif
98
99 #include <c-ctype.h>
100 #include <min-max.h>
101
102 #ifdef KERBEROS
103 #ifndef KERBEROS5
104 extern int krb_sendauth (
105
106
107 );
108 extern char *krb_realmofhost ();
109 #endif
110 #endif
111
112 static int socket_connection (char *, int);
113 static int pop_getline (popserver, char **);
114 static int sendline (popserver, const char *);
115 static int fullwrite (int, char *, int);
116 static int getok (popserver);
117 #if 0
118 static int gettermination (popserver);
119 #endif
120 static void pop_trash (popserver);
121 static char *find_crlf (char *, int);
122
123 #define ERROR_MAX 160
124
125
126 #define POP_PORT 110
127 #define POP_SERVICE "pop3"
128 #ifdef KERBEROS
129 #define KPOP_PORT 1109
130 #define KPOP_SERVICE "kpop"
131 #endif
132
133 char pop_error[ERROR_MAX];
134 bool pop_debug = false;
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 popserver
166 pop_open (char *host, char *username, char *password, int flags)
167 {
168 int sock;
169 popserver server;
170
171
172 if (! username)
173 {
174 username = getenv ("USER");
175 if (! (username && *username))
176 {
177 username = getlogin ();
178 if (! (username && *username))
179 {
180 struct passwd *passwd;
181 passwd = getpwuid (getuid ());
182 if (passwd && passwd->pw_name && *passwd->pw_name)
183 {
184 username = passwd->pw_name;
185 }
186 else
187 {
188 strcpy (pop_error, "Could not determine username");
189 return (0);
190 }
191 }
192 }
193 }
194
195
196
197
198
199 if (! host)
200 {
201 host = getenv ("MAILHOST");
202 }
203
204 #ifdef HESIOD
205 if ((! host) && (! (flags & POP_NO_HESIOD)))
206 {
207 struct hes_postoffice *office;
208 office = hes_getmailhost (username);
209 if (office && office->po_type && (! strcmp (office->po_type, "POP"))
210 && office->po_name && *office->po_name && office->po_host
211 && *office->po_host)
212 {
213 host = office->po_host;
214 username = office->po_name;
215 }
216 }
217 #endif
218
219 #ifdef MAILHOST
220 if (! host)
221 {
222 host = MAILHOST;
223 }
224 #endif
225
226 if (! host)
227 {
228 strcpy (pop_error, "Could not determine POP server");
229 return (0);
230 }
231
232
233 #ifdef KERBEROS
234 #define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
235 #else
236 #define DONT_NEED_PASSWORD 0
237 #endif
238
239 if ((! password) && (! DONT_NEED_PASSWORD))
240 {
241 if (! (flags & POP_NO_GETPASS))
242 {
243 password = getpass ("Enter POP password:");
244 }
245 if (! password)
246 {
247 strcpy (pop_error, "Could not determine POP password");
248 return (0);
249 }
250 }
251 if (password)
252 flags |= POP_NO_KERBEROS;
253 else
254 password = username;
255
256
257 sock = socket_connection (host, flags);
258 if (sock == -1)
259 return (0);
260
261 server = (popserver) malloc (sizeof (struct _popserver));
262 if (! server)
263 {
264 strcpy (pop_error, "Out of memory in pop_open");
265 return (0);
266 }
267 server->buffer = (char *) malloc (GETLINE_MIN);
268 if (! server->buffer)
269 {
270 strcpy (pop_error, "Out of memory in pop_open");
271 free ((char *) server);
272 return (0);
273 }
274
275 server->file = sock;
276 server->data = 0;
277 server->buffer_index = 0;
278 server->buffer_size = GETLINE_MIN;
279 server->in_multi = false;
280 server->trash_started = false;
281
282 if (getok (server))
283 return (0);
284
285
286
287
288 if (strnlen (username, ERROR_MAX - 6 + 1) == ERROR_MAX - 6 + 1)
289 {
290 pop_close (server);
291 strcpy (pop_error,
292 "Username too long; recompile pop.c with larger ERROR_MAX");
293 return (0);
294 }
295 sprintf (pop_error, "USER %s", username);
296
297 if (sendline (server, pop_error) || getok (server))
298 {
299 return (0);
300 }
301
302 if (strnlen (password, ERROR_MAX - 6 + 1) == ERROR_MAX - 6 + 1)
303 {
304 pop_close (server);
305 strcpy (pop_error,
306 "Password too long; recompile pop.c with larger ERROR_MAX");
307 return (0);
308 }
309 sprintf (pop_error, "PASS %s", password);
310
311 if (sendline (server, pop_error) || getok (server))
312 {
313 return (0);
314 }
315
316 return (server);
317 }
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332 int
333 pop_stat (popserver server, int *count, int *size)
334 {
335 char *fromserver;
336 char *end_ptr;
337
338 if (server->in_multi)
339 {
340 strcpy (pop_error, "In multi-line query in pop_stat");
341 return (-1);
342 }
343
344 if (sendline (server, "STAT") || (pop_getline (server, &fromserver) < 0))
345 return (-1);
346
347 if (strncmp (fromserver, "+OK ", 4))
348 {
349 if (0 == strncmp (fromserver, "-ERR", 4))
350 snprintf (pop_error, ERROR_MAX, "%s", fromserver);
351 else
352 {
353 strcpy (pop_error,
354 "Unexpected response from POP server in pop_stat");
355 pop_trash (server);
356 }
357 return (-1);
358 }
359
360 errno = 0;
361 *count = strtol (&fromserver[4], &end_ptr, 10);
362
363 if (fromserver + 4 == end_ptr || *end_ptr != ' ' || errno)
364 {
365 strcpy (pop_error, "Unexpected response from POP server in pop_stat");
366 pop_trash (server);
367 return (-1);
368 }
369
370 fromserver = end_ptr;
371
372 errno = 0;
373 *size = strtol (fromserver + 1, &end_ptr, 10);
374 if (fromserver + 1 == end_ptr || errno)
375 {
376 strcpy (pop_error, "Unexpected response from POP server in pop_stat");
377 pop_trash (server);
378 return (-1);
379 }
380
381 return (0);
382 }
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403 int
404 pop_list (popserver server, int message, int **IDs, int **sizes)
405 {
406 int how_many, i;
407 char *fromserver;
408
409 if (server->in_multi)
410 {
411 strcpy (pop_error, "In multi-line query in pop_list");
412 return (-1);
413 }
414
415 if (message)
416 how_many = 1;
417 else
418 {
419 int count, size;
420 if (pop_stat (server, &count, &size))
421 return (-1);
422 how_many = count;
423 }
424
425 *IDs = (int *) malloc ((how_many + 1) * sizeof (int));
426 *sizes = (int *) malloc ((how_many + 1) * sizeof (int));
427 if (! (*IDs && *sizes))
428 {
429 strcpy (pop_error, "Out of memory in pop_list");
430 return (-1);
431 }
432
433 if (message)
434 {
435 sprintf (pop_error, "LIST %d", message);
436 if (sendline (server, pop_error))
437 {
438 free ((char *) *IDs);
439 free ((char *) *sizes);
440 return (-1);
441 }
442 if (pop_getline (server, &fromserver) < 0)
443 {
444 free ((char *) *IDs);
445 free ((char *) *sizes);
446 return (-1);
447 }
448 if (strncmp (fromserver, "+OK ", 4))
449 {
450 if (! strncmp (fromserver, "-ERR", 4))
451 snprintf (pop_error, ERROR_MAX, "%s", fromserver);
452 else
453 {
454 strcpy (pop_error,
455 "Unexpected response from server in pop_list");
456 pop_trash (server);
457 }
458 free ((char *) *IDs);
459 free ((char *) *sizes);
460 return (-1);
461 }
462 (*IDs)[0] = atoi (&fromserver[4]);
463 fromserver = strchr (&fromserver[4], ' ');
464 if (! fromserver)
465 {
466 strcpy (pop_error,
467 "Badly formatted response from server in pop_list");
468 pop_trash (server);
469 free ((char *) *IDs);
470 free ((char *) *sizes);
471 return (-1);
472 }
473 (*sizes)[0] = atoi (fromserver);
474 (*IDs)[1] = (*sizes)[1] = 0;
475 return (0);
476 }
477 else
478 {
479 if (pop_multi_first (server, "LIST", &fromserver))
480 {
481 free ((char *) *IDs);
482 free ((char *) *sizes);
483 return (-1);
484 }
485 for (i = 0; i < how_many; i++)
486 {
487 if (pop_multi_next (server, &fromserver) <= 0)
488 {
489 free ((char *) *IDs);
490 free ((char *) *sizes);
491 return (-1);
492 }
493 (*IDs)[i] = atoi (fromserver);
494 fromserver = strchr (fromserver, ' ');
495 if (! fromserver)
496 {
497 strcpy (pop_error,
498 "Badly formatted response from server in pop_list");
499 free ((char *) *IDs);
500 free ((char *) *sizes);
501 pop_trash (server);
502 return (-1);
503 }
504 (*sizes)[i] = atoi (fromserver);
505 }
506 if (pop_multi_next (server, &fromserver) < 0)
507 {
508 free ((char *) *IDs);
509 free ((char *) *sizes);
510 return (-1);
511 }
512 else if (fromserver)
513 {
514 strcpy (pop_error,
515 "Too many response lines from server in pop_list");
516 free ((char *) *IDs);
517 free ((char *) *sizes);
518 return (-1);
519 }
520 (*IDs)[i] = (*sizes)[i] = 0;
521 return (0);
522 }
523 }
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545 int
546 pop_retrieve (popserver server, int message, int markfrom, char **msg_buf)
547 {
548 int *IDs, *sizes, bufsize, fromcount = 0, cp = 0;
549 char *ptr, *fromserver;
550 int ret;
551
552 if (server->in_multi)
553 {
554 strcpy (pop_error, "In multi-line query in pop_retrieve");
555 return (-1);
556 }
557
558 if (pop_list (server, message, &IDs, &sizes))
559 return (-1);
560
561 if (pop_retrieve_first (server, message, &fromserver))
562 {
563 return (-1);
564 }
565
566
567
568
569
570
571
572 bufsize = sizes[0] + (markfrom ? 5 : 0);
573 ptr = (char *)malloc (bufsize);
574 free ((char *) IDs);
575 free ((char *) sizes);
576
577 if (! ptr)
578 {
579 strcpy (pop_error, "Out of memory in pop_retrieve");
580 pop_retrieve_flush (server);
581 return (-1);
582 }
583
584 while ((ret = pop_retrieve_next (server, &fromserver)) >= 0)
585 {
586 if (! fromserver)
587 {
588 ptr[cp] = '\0';
589 *msg_buf = ptr;
590 return (cp);
591 }
592 if (markfrom && fromserver[0] == 'F' && fromserver[1] == 'r' &&
593 fromserver[2] == 'o' && fromserver[3] == 'm' &&
594 fromserver[4] == ' ')
595 {
596 if (++fromcount == 5)
597 {
598 bufsize += 5;
599 ptr = (char *)realloc (ptr, bufsize);
600 if (! ptr)
601 {
602 strcpy (pop_error, "Out of memory in pop_retrieve");
603 pop_retrieve_flush (server);
604 return (-1);
605 }
606 fromcount = 0;
607 }
608 ptr[cp++] = '>';
609 }
610 memcpy (&ptr[cp], fromserver, ret);
611 cp += ret;
612 ptr[cp++] = '\n';
613 }
614
615 free (ptr);
616 return (-1);
617 }
618
619 int
620 pop_retrieve_first (popserver server, int message, char **response)
621 {
622 sprintf (pop_error, "RETR %d", message);
623 return (pop_multi_first (server, pop_error, response));
624 }
625
626
627
628
629
630
631
632
633
634 int
635 pop_retrieve_next (popserver server, char **line)
636 {
637 return (pop_multi_next (server, line));
638 }
639
640 int
641 pop_retrieve_flush (popserver server)
642 {
643 return (pop_multi_flush (server));
644 }
645
646 int
647 pop_top_first (popserver server, int message, int lines, char **response)
648 {
649 sprintf (pop_error, "TOP %d %d", message, lines);
650 return (pop_multi_first (server, pop_error, response));
651 }
652
653
654
655
656
657
658
659
660
661 int
662 pop_top_next (popserver server, char **line)
663 {
664 return (pop_multi_next (server, line));
665 }
666
667 int
668 pop_top_flush (popserver server)
669 {
670 return (pop_multi_flush (server));
671 }
672
673 int
674 pop_multi_first (popserver server, const char *command, char **response)
675 {
676 if (server->in_multi)
677 {
678 strcpy (pop_error,
679 "Already in multi-line query in pop_multi_first");
680 return (-1);
681 }
682
683 if (sendline (server, command) || (pop_getline (server, response) < 0))
684 {
685 return (-1);
686 }
687
688 if (0 == strncmp (*response, "-ERR", 4))
689 {
690 snprintf (pop_error, ERROR_MAX, "%s", *response);
691 return (-1);
692 }
693 else if (0 == strncmp (*response, "+OK", 3))
694 {
695 for (*response += 3; **response == ' '; (*response)++) ;
696 server->in_multi = true;
697 return (0);
698 }
699 else
700 {
701 strcpy (pop_error,
702 "Unexpected response from server in pop_multi_first");
703 return (-1);
704 }
705 }
706
707
708
709
710
711
712
713
714
715
716 int
717 pop_multi_next (popserver server, char **line)
718 {
719 char *fromserver;
720 int ret;
721
722 if (! server->in_multi)
723 {
724 strcpy (pop_error, "Not in multi-line query in pop_multi_next");
725 return (-1);
726 }
727
728 ret = pop_getline (server, &fromserver);
729 if (ret < 0)
730 {
731 return (-1);
732 }
733
734 if (fromserver[0] == '.')
735 {
736 if (! fromserver[1])
737 {
738 *line = 0;
739 server->in_multi = false;
740 return (0);
741 }
742 else
743 {
744 *line = fromserver + 1;
745 return (ret - 1);
746 }
747 }
748 else
749 {
750 *line = fromserver;
751 return (ret);
752 }
753 }
754
755 int
756 pop_multi_flush (popserver server)
757 {
758 char *line;
759 int ret;
760
761 if (! server->in_multi)
762 {
763 return (0);
764 }
765
766 while ((ret = pop_multi_next (server, &line)))
767 {
768 if (ret < 0)
769 return (-1);
770 }
771
772 return (0);
773 }
774
775
776
777
778
779
780
781
782
783
784
785
786 int
787 pop_delete (popserver server, int message)
788 {
789 if (server->in_multi)
790 {
791 strcpy (pop_error, "In multi-line query in pop_delete");
792 return (-1);
793 }
794
795 sprintf (pop_error, "DELE %d", message);
796
797 if (sendline (server, pop_error) || getok (server))
798 return (-1);
799
800 return (0);
801 }
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816 int
817 pop_noop (popserver server)
818 {
819 if (server->in_multi)
820 {
821 strcpy (pop_error, "In multi-line query in pop_noop");
822 return (-1);
823 }
824
825 if (sendline (server, "NOOP") || getok (server))
826 return (-1);
827
828 return (0);
829 }
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845 int
846 pop_last (popserver server)
847 {
848 char *fromserver;
849
850 if (server->in_multi)
851 {
852 strcpy (pop_error, "In multi-line query in pop_last");
853 return (-1);
854 }
855
856 if (sendline (server, "LAST"))
857 return (-1);
858
859 if (pop_getline (server, &fromserver) < 0)
860 return (-1);
861
862 if (! strncmp (fromserver, "-ERR", 4))
863 {
864 snprintf (pop_error, ERROR_MAX, "%s", fromserver);
865 return (-1);
866 }
867 else if (strncmp (fromserver, "+OK ", 4))
868 {
869 strcpy (pop_error, "Unexpected response from server in pop_last");
870 pop_trash (server);
871 return (-1);
872 }
873 else
874 {
875 char *end_ptr;
876 int count;
877 errno = 0;
878 count = strtol (&fromserver[4], &end_ptr, 10);
879 if (fromserver + 4 == end_ptr || errno)
880 {
881 strcpy (pop_error, "Unexpected response from server in pop_last");
882 pop_trash (server);
883 return (-1);
884 }
885 return count;
886 }
887 }
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902 int
903 pop_reset (popserver server)
904 {
905 if (pop_retrieve_flush (server))
906 {
907 return (-1);
908 }
909
910 if (sendline (server, "RSET") || getok (server))
911 return (-1);
912
913 return (0);
914 }
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930 int
931 pop_quit (popserver server)
932 {
933 int ret = 0;
934
935 if (server->file >= 0)
936 {
937 if (pop_retrieve_flush (server))
938 {
939 ret = -1;
940 }
941
942 if (sendline (server, "QUIT") || getok (server))
943 {
944 ret = -1;
945 }
946
947 close (server->file);
948 }
949
950 free (server->buffer);
951 free ((char *) server);
952
953 return (ret);
954 }
955
956 #ifdef WINDOWSNT
957 static int have_winsock = 0;
958 #endif
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974 static int
975 socket_connection (char *host, int flags)
976 {
977 struct addrinfo *res, *it;
978 struct addrinfo hints;
979 int ret;
980 struct servent *servent;
981 struct sockaddr_in addr;
982 char found_port = 0;
983 const char *service;
984 int sock;
985 char *realhost;
986 #ifdef KERBEROS
987 #ifdef KERBEROS5
988 krb5_error_code rem;
989 krb5_context kcontext = 0;
990 krb5_auth_context auth_context = 0;
991 krb5_ccache ccdef;
992 krb5_principal client, server;
993 krb5_error *err_ret;
994 register char *cp;
995 #else
996 KTEXT ticket;
997 MSG_DAT msg_data;
998 CREDENTIALS cred;
999 Key_schedule schedule;
1000 int rem;
1001 #endif
1002 #endif
1003
1004 int try_count = 0;
1005 int connect_ok;
1006
1007 #ifdef WINDOWSNT
1008 {
1009 WSADATA winsockData;
1010 if (WSAStartup (0x101, &winsockData) == 0)
1011 have_winsock = 1;
1012 }
1013 #endif
1014
1015 memset (&addr, 0, sizeof (addr));
1016 addr.sin_family = AF_INET;
1017
1018
1019 #ifdef KERBEROS
1020 service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE;
1021 #else
1022 service = POP_SERVICE;
1023 #endif
1024
1025 #ifdef HESIOD
1026 if (! (flags & POP_NO_HESIOD))
1027 {
1028 servent = hes_getservbyname (service, "tcp");
1029 if (servent)
1030 {
1031 addr.sin_port = servent->s_port;
1032 found_port = 1;
1033 }
1034 }
1035 #endif
1036 if (! found_port)
1037 {
1038 servent = getservbyname (service, "tcp");
1039 if (servent)
1040 {
1041 addr.sin_port = servent->s_port;
1042 }
1043 else
1044 {
1045
1046 #ifdef KERBEROS
1047 addr.sin_port = htons ((flags & POP_NO_KERBEROS) ?
1048 POP_PORT : KPOP_PORT);
1049 #else
1050 addr.sin_port = htons (POP_PORT);
1051 #endif
1052 }
1053 }
1054
1055 #define POP_SOCKET_ERROR "Could not create socket for POP connection: "
1056
1057 sock = socket (PF_INET, SOCK_STREAM, 0);
1058 if (sock < 0)
1059 {
1060 snprintf (pop_error, ERROR_MAX, "%s%s",
1061 POP_SOCKET_ERROR, strerror (errno));
1062 return (-1);
1063
1064 }
1065
1066 memset (&hints, 0, sizeof (hints));
1067 hints.ai_socktype = SOCK_STREAM;
1068 hints.ai_flags = AI_CANONNAME;
1069 hints.ai_family = AF_INET;
1070 do
1071 {
1072 ret = getaddrinfo (host, service, &hints, &res);
1073 try_count++;
1074 if (ret != 0 && (ret != EAI_AGAIN || try_count == 5))
1075 {
1076 strcpy (pop_error, "Could not determine POP server's address");
1077 return (-1);
1078 }
1079 } while (ret != 0);
1080
1081 for (it = res; it; it = it->ai_next)
1082 if (it->ai_addrlen == sizeof addr)
1083 {
1084 struct sockaddr_in *in_a = (struct sockaddr_in *) it->ai_addr;
1085 addr.sin_addr = in_a->sin_addr;
1086 if (! connect (sock, (struct sockaddr *) &addr, sizeof addr))
1087 break;
1088 }
1089 connect_ok = it != NULL;
1090 if (connect_ok)
1091 {
1092 realhost = alloca (strlen (it->ai_canonname) + 1);
1093 strcpy (realhost, it->ai_canonname);
1094 }
1095 freeaddrinfo (res);
1096
1097 #define CONNECT_ERROR "Could not connect to POP server: "
1098
1099 if (! connect_ok)
1100 {
1101 CLOSESOCKET (sock);
1102 snprintf (pop_error, ERROR_MAX, "%s%s", CONNECT_ERROR, strerror (errno));
1103 return (-1);
1104
1105 }
1106
1107 #ifdef KERBEROS
1108
1109 #define KRB_ERROR "Kerberos error connecting to POP server: "
1110 if (! (flags & POP_NO_KERBEROS))
1111 {
1112 #ifdef KERBEROS5
1113 rem = krb5_init_context (&kcontext);
1114 if (rem)
1115 {
1116 krb5error:
1117 if (auth_context)
1118 krb5_auth_con_free (kcontext, auth_context);
1119 if (kcontext)
1120 krb5_free_context (kcontext);
1121 snprintf (pop_error, ERROR_MAX, "%s%s",
1122 KRB_ERROR, error_message (rem));
1123 CLOSESOCKET (sock);
1124 return (-1);
1125 }
1126
1127 rem = krb5_auth_con_init (kcontext, &auth_context);
1128 if (rem)
1129 goto krb5error;
1130
1131 rem = krb5_cc_default (kcontext, &ccdef);
1132 if (rem)
1133 goto krb5error;
1134
1135 rem = krb5_cc_get_principal (kcontext, ccdef, &client);
1136 if (rem)
1137 goto krb5error;
1138
1139 for (cp = realhost; *cp; cp++)
1140 *cp = c_tolower (*cp);
1141
1142 rem = krb5_sname_to_principal (kcontext, realhost,
1143 POP_SERVICE, FALSE, &server);
1144 if (rem)
1145 goto krb5error;
1146
1147 rem = krb5_sendauth (kcontext, &auth_context,
1148 (krb5_pointer) &sock, (char *) "KPOPV1.0",
1149 client, server,
1150 AP_OPTS_MUTUAL_REQUIRED,
1151 0,
1152 0,
1153 ccdef,
1154 &err_ret,
1155 0,
1156 0);
1157 krb5_free_principal (kcontext, server);
1158 if (rem)
1159 {
1160 int pop_error_len = snprintf (pop_error, ERROR_MAX, "%s%s",
1161 KRB_ERROR, error_message (rem));
1162 #if defined HAVE_KRB5_ERROR_TEXT
1163 if (err_ret && err_ret->text.length)
1164 {
1165 int errlen = err_ret->text.length;
1166 snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len,
1167 " [server says '%.*s']", errlen, err_ret->text.data);
1168 }
1169 #elif defined HAVE_KRB5_ERROR_E_TEXT
1170 if (err_ret && err_ret->e_text && **err_ret->e_text)
1171 snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len,
1172 " [server says '%s']", *err_ret->e_text);
1173 #endif
1174 if (err_ret)
1175 krb5_free_error (kcontext, err_ret);
1176 krb5_auth_con_free (kcontext, auth_context);
1177 krb5_free_context (kcontext);
1178
1179 CLOSESOCKET (sock);
1180 return (-1);
1181 }
1182 #else
1183 ticket = (KTEXT) malloc (sizeof (KTEXT_ST));
1184 rem = krb_sendauth (0L, sock, ticket, "pop", realhost,
1185 (char *) krb_realmofhost (realhost),
1186 (unsigned long) 0, &msg_data, &cred, schedule,
1187 (struct sockaddr_in *) 0,
1188 (struct sockaddr_in *) 0,
1189 "KPOPV0.1");
1190 free ((char *) ticket);
1191 if (rem != KSUCCESS)
1192 {
1193 snprintf (pop_error, ERROR_MAX, "%s%s", KRB_ERROR, krb_err_txt[rem]);
1194 CLOSESOCKET (sock);
1195 return (-1);
1196 }
1197 #endif
1198 }
1199 #endif
1200
1201 return (sock);
1202 }
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227 static int
1228 pop_getline (popserver server, char **line)
1229 {
1230 #define GETLINE_ERROR "Error reading from server: "
1231
1232 int ret;
1233 int search_offset = 0;
1234
1235 if (server->data)
1236 {
1237 char *cp = find_crlf (server->buffer + server->buffer_index,
1238 server->data);
1239 if (cp)
1240 {
1241 int found;
1242 int data_used;
1243
1244 found = server->buffer_index;
1245 data_used = (cp + 2) - server->buffer - found;
1246
1247 *cp = '\0';
1248 server->data -= data_used;
1249 server->buffer_index += data_used;
1250
1251 if (pop_debug)
1252
1253
1254 fprintf (stderr, "<<< %s\n", server->buffer + found);
1255 *line = server->buffer + found;
1256 return (data_used - 2);
1257 }
1258 else
1259 {
1260 memmove (server->buffer, server->buffer + server->buffer_index,
1261 server->data);
1262
1263
1264
1265
1266
1267
1268
1269 search_offset = server->data - 1;
1270 server->buffer_index = 0;
1271 }
1272 }
1273 else
1274 {
1275 server->buffer_index = 0;
1276 }
1277
1278 while (true)
1279 {
1280
1281
1282
1283 if (server->data == server->buffer_size - 1)
1284 {
1285 server->buffer_size += GETLINE_INCR;
1286 server->buffer = (char *)realloc (server->buffer, server->buffer_size);
1287 if (! server->buffer)
1288 {
1289 strcpy (pop_error, "Out of memory in pop_getline");
1290 pop_trash (server);
1291 break;
1292 }
1293 }
1294 ret = RECV (server->file, server->buffer + server->data,
1295 server->buffer_size - server->data - 1, 0);
1296 if (ret < 0)
1297 {
1298 snprintf (pop_error, ERROR_MAX, "%s%s",
1299 GETLINE_ERROR, strerror (errno));
1300 pop_trash (server);
1301 break;
1302 }
1303 else if (ret == 0)
1304 {
1305 strcpy (pop_error, "Unexpected EOF from server in pop_getline");
1306 pop_trash (server);
1307 break;
1308 }
1309 else
1310 {
1311 char *cp;
1312 server->data += ret;
1313 server->buffer[server->data] = '\0';
1314
1315 cp = find_crlf (server->buffer + search_offset,
1316 server->data - search_offset);
1317 if (cp)
1318 {
1319 int data_used = (cp + 2) - server->buffer;
1320 *cp = '\0';
1321 server->data -= data_used;
1322 server->buffer_index = data_used;
1323
1324 if (pop_debug)
1325 fprintf (stderr, "<<< %s\n", server->buffer);
1326 *line = server->buffer;
1327 return (data_used - 2);
1328 }
1329
1330
1331 search_offset += ret - 1;
1332 }
1333 }
1334
1335 return -1;
1336 }
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356 static int
1357 sendline (popserver server, const char *line)
1358 {
1359 #define SENDLINE_ERROR "Error writing to POP server: "
1360 int ret;
1361 char *buf;
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375 buf = alloca (strlen (line) + 3);
1376 strcpy (stpcpy (buf, line), "\r\n");
1377 ret = fullwrite (server->file, buf, strlen (buf));
1378
1379 if (ret < 0)
1380 {
1381 pop_trash (server);
1382 snprintf (pop_error, ERROR_MAX, "%s%s", SENDLINE_ERROR, strerror (errno));
1383 return (ret);
1384 }
1385
1386 if (pop_debug)
1387 fprintf (stderr, ">>> %s\n", line);
1388
1389 return (0);
1390 }
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400 static int
1401 fullwrite (int fd, char *buf, int nbytes)
1402 {
1403 char *cp;
1404 int ret = 0;
1405
1406 cp = buf;
1407 while (nbytes && ((ret = SEND (fd, cp, nbytes, 0)) > 0))
1408 {
1409 cp += ret;
1410 nbytes -= ret;
1411 }
1412
1413 return (ret);
1414 }
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430 static int
1431 getok (popserver server)
1432 {
1433 char *fromline;
1434
1435 if (pop_getline (server, &fromline) < 0)
1436 {
1437 return (-1);
1438 }
1439
1440 if (! strncmp (fromline, "+OK", 3))
1441 return (0);
1442 else if (! strncmp (fromline, "-ERR", 4))
1443 {
1444 snprintf (pop_error, ERROR_MAX, "%s", fromline);
1445 return (-1);
1446 }
1447 else
1448 {
1449 strcpy (pop_error,
1450 "Unexpected response from server; expecting +OK or -ERR");
1451 pop_trash (server);
1452 return (-1);
1453 }
1454 }
1455
1456 #if 0
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467 static int
1468 gettermination (server)
1469 popserver server;
1470 {
1471 char *fromserver;
1472
1473 if (pop_getline (server, &fromserver) < 0)
1474 return (-1);
1475
1476 if (strcmp (fromserver, "."))
1477 {
1478 strcpy (pop_error,
1479 "Unexpected response from server in gettermination");
1480 pop_trash (server);
1481 return (-1);
1482 }
1483
1484 return (0);
1485 }
1486 #endif
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500 void
1501 pop_close (popserver server)
1502 {
1503 pop_trash (server);
1504 free ((char *) server);
1505
1506 return;
1507 }
1508
1509
1510
1511
1512
1513
1514
1515
1516 static void
1517 pop_trash (popserver server)
1518 {
1519 if (server->file >= 0)
1520 {
1521
1522 if (server->trash_started)
1523 return;
1524 server->trash_started = true;
1525
1526 sendline (server, "RSET");
1527 sendline (server, "QUIT");
1528
1529 CLOSESOCKET (server->file);
1530 server->file = -1;
1531 if (server->buffer)
1532 {
1533 free (server->buffer);
1534 server->buffer = 0;
1535 }
1536 }
1537
1538 #ifdef WINDOWSNT
1539 if (have_winsock)
1540 WSACleanup ();
1541 #endif
1542 }
1543
1544
1545
1546
1547
1548 static char *
1549 find_crlf (char *in_string, int len)
1550 {
1551 while (len--)
1552 {
1553 if (*in_string == '\r')
1554 {
1555 if (*++in_string == '\n')
1556 return (in_string - 1);
1557 }
1558 else
1559 in_string++;
1560 }
1561 return (0);
1562 }
1563
1564 #ifdef WINDOWSNT
1565
1566
1567
1568 int (WINAPI *pfn_getaddrinfo) (const char *, const char *,
1569 const struct addrinfo *, struct addrinfo **);
1570 void (WINAPI *pfn_freeaddrinfo) (struct addrinfo *);
1571
1572 static int
1573 load_ws2 (void)
1574 {
1575 static int ws2_loaded = 0;
1576
1577 if (!ws2_loaded)
1578 {
1579 HANDLE ws2_lib = LoadLibrary ("Ws2_32.dll");
1580
1581 if (ws2_lib != NULL)
1582 {
1583 ws2_loaded = 1;
1584 pfn_getaddrinfo = (void *) GetProcAddress (ws2_lib, "getaddrinfo");
1585 pfn_freeaddrinfo = (void *) GetProcAddress (ws2_lib, "freeaddrinfo");
1586
1587
1588 if (pfn_getaddrinfo == NULL)
1589 pfn_freeaddrinfo = NULL;
1590 else if (pfn_freeaddrinfo == NULL)
1591 pfn_getaddrinfo = NULL;
1592 }
1593 }
1594 if (!ws2_loaded)
1595 {
1596 errno = ENETDOWN;
1597 return -1;
1598 }
1599 return 0;
1600 }
1601
1602
1603 int
1604 sys_getaddrinfo (const char *node, const char *service,
1605 const struct addrinfo *hints, struct addrinfo **res)
1606 {
1607 int rc;
1608
1609 if (load_ws2 () != 0)
1610 {
1611 errno = ENETDOWN;
1612 return WSANO_RECOVERY;
1613 }
1614
1615 if (pfn_getaddrinfo)
1616 rc = pfn_getaddrinfo (node, service, hints, res);
1617 else
1618 {
1619 int port = 0;
1620 struct hostent *host_info;
1621 struct gai_storage {
1622 struct addrinfo addrinfo;
1623 struct sockaddr_in sockaddr_in;
1624 } *gai_storage;
1625
1626
1627 if (hints && (hints->ai_flags & ~(AI_CANONNAME)) != 0)
1628 return WSAEINVAL;
1629
1630 if (!node)
1631 return WSAHOST_NOT_FOUND;
1632
1633 if (service)
1634 {
1635 const char *protocol =
1636 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
1637 struct servent *srv = getservbyname (service, protocol);
1638
1639 if (srv)
1640 port = srv->s_port;
1641 else
1642 return WSAHOST_NOT_FOUND;
1643 }
1644
1645 gai_storage = calloc (1, sizeof *gai_storage);
1646 gai_storage->sockaddr_in.sin_port = port;
1647 host_info = gethostbyname (node);
1648 if (host_info)
1649 {
1650 memcpy (&gai_storage->sockaddr_in.sin_addr,
1651 host_info->h_addr, host_info->h_length);
1652 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
1653 }
1654 else
1655 {
1656 free (gai_storage);
1657 return WSAHOST_NOT_FOUND;
1658 }
1659
1660 gai_storage->addrinfo.ai_addr =
1661 (struct sockaddr *)&gai_storage->sockaddr_in;
1662 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
1663 if (hints && (hints->ai_flags & AI_CANONNAME) != 0)
1664 {
1665 gai_storage->addrinfo.ai_canonname = strdup (host_info->h_name);
1666 if (!gai_storage->addrinfo.ai_canonname)
1667 {
1668 free (gai_storage);
1669 return WSA_NOT_ENOUGH_MEMORY;
1670 }
1671 }
1672 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
1673 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
1674 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
1675 gai_storage->addrinfo.ai_next = NULL;
1676
1677 *res = &gai_storage->addrinfo;
1678 rc = 0;
1679 }
1680
1681 return rc;
1682 }
1683
1684 void
1685 sys_freeaddrinfo (struct addrinfo *ai)
1686 {
1687 if (load_ws2 () != 0)
1688 {
1689 errno = ENETDOWN;
1690 return;
1691 }
1692
1693 if (pfn_freeaddrinfo)
1694 pfn_freeaddrinfo (ai);
1695 else
1696 {
1697 if (ai->ai_canonname)
1698 free (ai->ai_canonname);
1699 free (ai);
1700 }
1701 }
1702 #endif
1703 #endif