Mercurial > hgrepos > hgweb.cgi > imapext
comparison APOPtools/apopcall.c @ 4:d741b3ecc917 draft
imapext-2007f
author | HIROSE Yuuji <yuuji@gentei.org> |
---|---|
date | Thu, 30 Oct 2014 00:03:05 +0900 |
parents | 28a55bc1110c |
children |
comparison
equal
deleted
inserted
replaced
3:2366b362676d | 4:d741b3ecc917 |
---|---|
522 } else { | 522 } else { |
523 printf("This program can be used only via SSL connection.<br>\n"); | 523 printf("This program can be used only via SSL connection.<br>\n"); |
524 printf("このユーティリティはSSL接続時のみ有効です.<br>\n"); | 524 printf("このユーティリティはSSL接続時のみ有効です.<br>\n"); |
525 } | 525 } |
526 } | 526 } |
527 #include <stdio.h> | |
528 #include <stdlib.h> | |
529 #include <string.h> | |
530 #include <unistd.h> | |
531 #include <sys/types.h> | |
532 #include <sys/wait.h> | |
533 #include <sys/stat.h> | |
534 #include <pwd.h> | |
535 #ifdef SHADOW_PASSWD | |
536 #include <shadow.h> | |
537 #endif | |
538 | |
539 #ifndef APOPPASSWD | |
540 #define APOPPASSWD "/usr/local/bin/apoppasswd" | |
541 #endif | |
542 #ifndef APOPFILEBASE | |
543 #define APOPFILEBASE ".apop" | |
544 #endif | |
545 #ifndef XADDR_DELIM | |
546 #define XADDR_DELIM ('-') | |
547 #endif | |
548 | |
549 char *myname; | |
550 | |
551 int ishexa(int c) { | |
552 strchr("0123456789ABCDFabcdef", c) ? 1 : 0; | |
553 } | |
554 | |
555 put_form(email, pass, new, new2, suffix, hidden, auth, force) | |
556 char *email, *pass, *new, *new2, *suffix; | |
557 int hidden, auth, force; | |
558 /* auth = 0: old password | |
559 1: base addresse's mail password | |
560 2: unix password */ | |
561 { | |
562 char *authtype[] = {"old", "base", "unix"}; | |
563 char *var[] = {"email", "pass", "new", "new2", "auth", ""}; | |
564 char *val[] = {email, pass, new, new2, authtype[auth]}; | |
565 char *prm[] = {"", /* "ユーザ名", */ | |
566 auth ? | |
567 ((auth==1) | |
568 ? "基本メイルアドレス用パスワード<br>Password for Basic Mail address" | |
569 : "UNIXログインパスワード<br>UNIX login Password") | |
570 : "古いメイルパスワード<br>Old Mail Password", | |
571 "新しいメイルパスワード<br>New Mail Password", | |
572 "新パスワードをもう一回(確認)<br>New Mail Password Again", | |
573 ""}; | |
574 int h=0, i; | |
575 | |
576 printf("<form method=POST action\"./%s\">\n", myname); | |
577 printf(" <table border=1>\n"); | |
578 for (i=0; var[i][0]; i++) { | |
579 h = hidden || strstr("email,suffix,auth", var[i]); | |
580 if (prm[i][0]) { | |
581 printf("<tr><td>%s</td><td>", prm[i]); | |
582 } else { | |
583 } | |
584 printf("<input name=%s %svalue=\"%s\" length=40 maxlength=40>\n", | |
585 var[i], | |
586 h ? "type=hidden " | |
587 : (strstr(prm[i], "パスワード") ? "type=password " : "<br>"), | |
588 val[i]); | |
589 if (!strcmp(var[i], "suffix")) { | |
590 /* ここでは suffix を入れさせない方がいいかも */ | |
591 /* 表向きのメイルアドレスを表示しておく */ | |
592 printf("%s", email); | |
593 /* if (suffix[0]) { | |
594 printf("-%s", suffix); | |
595 } */ | |
596 if (auth) | |
597 printf("<br>(新規作成:New Account)"); | |
598 } | |
599 if (prm[i][0]) | |
600 printf("</td></tr>"); | |
601 printf("\n"); | |
602 } | |
603 | |
604 printf("</table>\n"); | |
605 if (force) | |
606 printf("<input name=force type=hidden value=ON>\n"); | |
607 if (auth) { | |
608 char *a[] = {"basic", "unix"}; | |
609 printf("<input type=hidden name=auth value=\"%s\">\n", a[auth-1]); | |
610 } | |
611 printf("<input name=OK value=OK type=submit>\n"); | |
612 printf("<input name=RESET value=RESET type=reset>\n"); | |
613 printf("</form>\n"); | |
614 fflush(stdout); | |
615 } | |
616 | |
617 char *decode(char *code) { | |
618 int l=1+strlen(code); | |
619 int i, c, d; | |
620 char *ret = (char*)malloc(l*sizeof(char)); | |
621 char *p = code; | |
622 memset(ret, 0, l); | |
623 for (i=0; i<strlen(code); i++) { | |
624 if (code[i] == '+') code[i] = ' '; | |
625 } | |
626 while (code[0] && (p=strchr(code, '%')) | |
627 && ishexa(*(p+1)) && ishexa(*(p+2))) { | |
628 *(p++) = '\0'; | |
629 strncat(ret, code, l); | |
630 c = (islower(*p) ? toupper(*p) : *p) - '0'; | |
631 p++; | |
632 d = (islower(*p) ? toupper(*p) : *p) - '0'; | |
633 if (c > 9) c -= ('A'-'9'-1); | |
634 if (d > 9) d -= ('A'-'9'-1); | |
635 ret[strlen(ret)] = c*16+d; | |
636 code = p+1; | |
637 } | |
638 if (code[0]) strncat(ret, code, l); | |
639 return ret; | |
640 } | |
641 | |
642 #define BSIZE 8192 | |
643 char **decode_post() { | |
644 char *buf = (char*)malloc(BSIZE*sizeof(char)); | |
645 char **post, *p = buf; | |
646 int n=0, i; | |
647 post = (char**)calloc(1, sizeof(char*)); | |
648 *buf = '\0'; | |
649 fgets(buf, BSIZE, stdin); | |
650 if (strchr("\n\r", buf[strlen(buf)-1])) /* chop */ | |
651 buf[strlen(buf)-1] = '\0'; | |
652 while (buf[0] && NULL != (p=strchr(buf, '&'))) { | |
653 *p = '\0'; | |
654 post[n] = (char*)malloc((p-buf+1)*sizeof(char)); | |
655 strcpy(post[n], buf); | |
656 n++; | |
657 post = (char**)realloc(post, (1+n)*sizeof(char*)); | |
658 buf = 1+p; | |
659 } | |
660 if (buf[0]) post[n++] = buf; | |
661 /* decode URL encoded */ | |
662 for (i=0; i < n; i++) { | |
663 char *p; | |
664 p=post[i]; | |
665 post[i] = decode(p); | |
666 } | |
667 post[i] = ""; /* terminator */ | |
668 return post; | |
669 } | |
670 | |
671 void footer() { | |
672 puts("</body>\n</html>"); | |
673 fflush(stdout); | |
674 } | |
675 | |
676 void fail() { | |
677 printf("パスワード更新に失敗しました<br>\n"); | |
678 printf("<a href=\"./\">やり直し</a><br>\n"); | |
679 footer(); | |
680 exit(1); | |
681 } | |
682 void success(char *email) { | |
683 printf("<hr>メイルアカウント %s 用のパスワード更新は完了しました。<br>\n", | |
684 email); | |
685 footer(); | |
686 exit(0); | |
687 } | |
688 | |
689 int apopfile_existp(char *home, char *suffix, uid_t uid) { | |
690 struct stat st; | |
691 int s; | |
692 int len = strlen(home) + 1 | |
693 + strlen(APOPFILEBASE) + strlen(suffix) + 3; | |
694 char *apopfile = (char*)malloc(len); | |
695 if (suffix[0]) { | |
696 snprintf(apopfile, len, "%s/%s%c%s%c", | |
697 home, APOPFILEBASE, XADDR_DELIM, suffix, 0); | |
698 } else { | |
699 snprintf(apopfile, len, "%s/%s%c", home, APOPFILEBASE, 0); | |
700 } | |
701 seteuid(uid); | |
702 s = stat(apopfile, &st); | |
703 seteuid(0); | |
704 memset(apopfile, '\0', strlen(apopfile)); | |
705 free(apopfile); | |
706 return !s; | |
707 } | |
708 | |
709 #ifndef QMAILCONTROL | |
710 # define QMAILCONTROL "/var/qmail/control" | |
711 #endif | |
712 #ifndef MAILTMPLEN | |
713 # define MAILTMPLEN 1024 | |
714 #endif | |
715 | |
716 /* Convert virtual domain user | |
717 */ | |
718 char* conv_virtualdomain(char *account) { | |
719 char *dom = strchr(account, '@'), *p; | |
720 char vd[MAILTMPLEN+1], rewrite[MAILTMPLEN+1], previous[MAILTMPLEN+1]; | |
721 FILE *vdfd; | |
722 int match=0; | |
723 char buf[MAILTMPLEN+1], *s; | |
724 snprintf(vd, MAILTMPLEN, "%s/%s", QMAILCONTROL, "virtualdomains"); | |
725 if (NULL == dom) return account; | |
726 dom++; /* set position of domain part beginning */ | |
727 if (dom && NULL != (vdfd = fopen (vd, "r"))) { | |
728 int l = strlen(dom); | |
729 int L = strlen(account); | |
730 while ((s=fgets(buf, MAILTMPLEN, vdfd))) { | |
731 if (p=strchr(s, '#')) | |
732 *p = '\0'; /* zap comments */ | |
733 if (!strchr(buf, ':')) | |
734 continue; | |
735 while (s && (strrchr(s, '\n') || strrchr(s, '\r') || strrchr(s, ' '))) | |
736 s[strlen(s)-1] = '\0'; | |
737 if (!strncmp(account, s, L) && s[L] == ':' && s[L+1]) { /* user matches */ | |
738 match = 3; | |
739 snprintf(rewrite, MAILTMPLEN, "%s-%s", s+L+1, account); | |
740 break; | |
741 } | |
742 if (!strncmp(dom, s, l) && s[l] == ':' && s[l+1]) { /* domain matches */ | |
743 match = 2; | |
744 snprintf(rewrite, MAILTMPLEN, "%s%c%s", s+l+1, XADDR_DELIM, account); | |
745 continue; | |
746 } | |
747 if (match < 2 && s[0] == '.') { /* if domain described in wildcard */ | |
748 if (p=strchr(s, ':')) { | |
749 *p = '\0'; | |
750 if (!strcmp(dom+(strlen(dom)-strlen(s)), s)) { | |
751 if (match == 0 | |
752 || strlen(previous) < strlen(s)) { | |
753 match = 1; | |
754 strncpy(previous, s, MAILTMPLEN); | |
755 snprintf(rewrite, MAILTMPLEN, "%s%c%s", p+1, XADDR_DELIM, account); | |
756 } | |
757 } | |
758 } | |
759 } | |
760 } | |
761 fclose(vdfd); | |
762 if (match) { | |
763 p = strchr(rewrite, '@'); | |
764 /* fprintf(stderr, "m=%d, rwr=[%s]\n", match, rewrite); */ | |
765 if (p) { | |
766 *p = '\0'; | |
767 } | |
768 /* fprintf(stderr, "rwr=[%s]\n", rewrite); */ | |
769 s = malloc(strlen(rewrite)+1); | |
770 strncpy(s, rewrite, strlen(rewrite)+1); | |
771 memset(vd, 0, sizeof(vd)); | |
772 memset(rewrite, 0, sizeof(rewrite)); | |
773 memset(previous, 0, sizeof(previous)); | |
774 return s; | |
775 } | |
776 } | |
777 /* Then, compare with locals */ | |
778 snprintf(vd, MAILTMPLEN, "%s/%s", QMAILCONTROL, "locals"); | |
779 if (NULL != (vdfd=fopen(vd, "r"))) { | |
780 while (s=fgets(buf, MAILTMPLEN, vdfd)) { | |
781 if (p=strchr(s, '#')) *p = '\0'; /* zap after comment mark # */ | |
782 while (*s && (strrchr(s, '\r')||strrchr(s, '\n') | |
783 ||strrchr(s, ' ')||strrchr(s, '\t'))) { | |
784 *(s+strlen(s)-1) = '\0'; | |
785 } | |
786 while (*s && (*s == '\t' || *s == ' ')) s++; | |
787 if (!strncmp(s, dom, strlen(s))) { /* matches with local domain */ | |
788 int len = dom-account-1; | |
789 p = (char*)malloc(len+1); | |
790 memset(p, '\0', len+1); | |
791 strncpy(p, account, len); | |
792 return p; | |
793 } | |
794 } | |
795 } | |
796 return NULL; /* invalid domain */ | |
797 /* return account; return itself */ | |
798 } | |
799 | |
800 void apopcall(char **args) { | |
801 int i=0, sc=0; | |
802 pid_t pid; | |
803 char *email="", *suffix="", *pass="", *new="", *new2 = "", *home=""; | |
804 char buf[BUFSIZ], auth, *user; | |
805 FILE *child, *result; | |
806 while (args[i][0]) { | |
807 /* printf("[%s]<br>\n", args[i]); */ | |
808 if (!strncmp("email=", args[i], 6)) { | |
809 email = args[i]+6; | |
810 } else if (!strncmp("suffix=", args[i], 7)) { | |
811 suffix = args[i]+7; | |
812 } else if (!strncmp("pass=", args[i], 5)) { | |
813 pass = args[i]+5; | |
814 } else if (!strncmp("new=", args[i], 4)) { | |
815 new = args[i]+4; | |
816 } else if (!strncmp("new2=", args[i], 5)) { | |
817 new2 = args[i]+5; | |
818 } else if (!strncmp("auth=", args[i], 5)) { | |
819 /* "this" or "base" or "unix" */ | |
820 auth = args[i][5]; | |
821 } | |
822 i++; | |
823 } | |
824 /* Make a backup of original e-mail address */ | |
825 /* user = (char*)malloc(1+strlen(email)); | |
826 strcpy(user, email); | |
827 */ | |
828 user = conv_virtualdomain(email); | |
829 if (NULL == user) { | |
830 printf("そのようなドメインは無効です(%s)<br>\n", strchr(email, '@')); | |
831 printf("入力したメイルアドレスを確認してやり直してください.<br>\n"); | |
832 fail(); | |
833 } | |
834 if (strchr(user, XADDR_DELIM)) { | |
835 char *p = malloc(1+strlen(user)); | |
836 char *q = NULL; | |
837 struct passwd *pwd; | |
838 /* printf("user=[%s]<br>\n", user); */ | |
839 | |
840 memset(p, '\0', 1+strlen(user)); | |
841 strcpy(p, user); | |
842 while (!(pwd=getpwnam(p)) && (q=strrchr(p, XADDR_DELIM))) { | |
843 fflush(stdout); | |
844 *q = '\0'; | |
845 } | |
846 if (pwd && q) { | |
847 q = user+(q-p)+1; | |
848 user=p; | |
849 suffix=q; | |
850 } | |
851 } | |
852 if (user[0] && new[0] && new2[0]) { | |
853 int tochild[2], toparent[2]; | |
854 pid_t pid; | |
855 int argc=0; | |
856 char **argv; | |
857 struct passwd *pswd; | |
858 char *pstr; | |
859 | |
860 if (!(pswd=getpwnam(user))) { | |
861 printf("Unkown user %s.\n", user); | |
862 fflush(stdout); | |
863 fail(); | |
864 } | |
865 pstr = pswd->pw_passwd; | |
866 #ifdef SHADOW_PASSWD | |
867 { struct spwd *ss = getspnam(user); | |
868 pstr = (char*)ss->sp_pwdp; | |
869 } | |
870 #endif | |
871 home=pswd->pw_dir; | |
872 argv = (char**)calloc(4, sizeof(char*)); | |
873 argv[argc++] = "apoppasswd"; | |
874 argv[argc++] = "-s"; | |
875 argv[argc++] = "-c"; | |
876 /* if old password does not exist, | |
877 then check UNIX password */ | |
878 #if 0 | |
879 if (apopfile_existp(home, suffix, pswd->pw_uid)) { /* no apop-ext exists */ | |
880 /* そのまま */ | |
881 } else if (apopfile_existp(home, "", pswd->pw_uid)) {/* check base mail password */ | |
882 argv = (char**)realloc(argv, (argc+2)*sizeof(char*)); | |
883 argv[argc++] = "-b"; | |
884 } | |
885 #endif | |
886 switch (auth) { | |
887 case 'b': case 'B': | |
888 if (apopfile_existp(home, "", pswd->pw_uid)) { | |
889 argv = (char**)realloc(argv, (argc+2)*sizeof(char*)); | |
890 argv[argc++] = "-b"; | |
891 } else { | |
892 printf("基本アドレスのパスワードファイルがありません<br>\n"); | |
893 fail(); | |
894 } | |
895 break; | |
896 case 'u': case 'U': | |
897 if (strcmp(pstr, (char*)crypt(pass, pstr))) { | |
898 printf("UNIX Password not correct.<br>\n"); | |
899 /* printf("[%s]vs.[%s]<br>\n", | |
900 pswd->pw_passwd, crypt(pass, pswd->pw_passwd)); */ | |
901 printf("UNIXパスワードと一致しません.<br>\n"); | |
902 fflush(stdout); | |
903 fail(); | |
904 } | |
905 } | |
906 | |
907 if (strlen(new) < 8 || strlen(new2) < 8) { | |
908 printf("New mail password must be more than 7 characters.<br>\n"); | |
909 printf("メイルパスワードは8文字以上にしてください。<br>\n"); | |
910 fflush(stdout); | |
911 fail(); | |
912 } | |
913 if (suffix[0]) { | |
914 argv = (char**)realloc(argv, (argc+3)*sizeof(char*)); | |
915 argv[argc++] = "-e"; | |
916 argv[argc++] = suffix; | |
917 | |
918 } | |
919 argv[argc++] = NULL; | |
920 if (setgid(pswd->pw_gid) || 0 != setuid(pswd->pw_uid)) { | |
921 printf("Cannot switch to %s\n", user); | |
922 printf("uid=%d, gid=%d<br>\n", pswd->pw_gid, pswd->pw_uid); | |
923 printf("メイルパスワード変更サーバの設定不良の可能性があるので<br>\n"); | |
924 printf("お手数ですがこの画面のコピーを添えてシステム管理者"); | |
925 printf("まで御連絡下さい。<br>\n"); | |
926 fflush(stdout); | |
927 fail(); | |
928 } | |
929 | |
930 /* OK, start apopasswd */ | |
931 if (pipe(tochild)+pipe(toparent)) { | |
932 printf("Cannot create pipe\n"); | |
933 fail(); | |
934 } | |
935 if ((pid=fork()) > 0) { | |
936 FILE *child = fdopen(tochild[1], "w"); | |
937 close(tochild[0]); | |
938 close(toparent[1]); | |
939 fprintf(child, "PASS %s\nNEW %s\nNEW2 %s\n", | |
940 pass, new, new2); | |
941 fflush(child); | |
942 fclose(child); | |
943 | |
944 } else if (pid == -1) { | |
945 printf("Cannot fork\n"); | |
946 fail(); | |
947 } else { | |
948 char *pe = malloc(6+strlen(pswd->pw_dir)); | |
949 close(tochild[1]); | |
950 close(toparent[0]); | |
951 dup2(tochild[0], 0); | |
952 dup2(toparent[1], 1); | |
953 | |
954 /* setuid section */ | |
955 | |
956 strcpy(pe, "HOME="); | |
957 strcat(pe, pswd->pw_dir); | |
958 if (putenv(pe)) { | |
959 puts("ga-n! arichan gakkari<br>"); | |
960 } | |
961 execv(APOPPASSWD, argv); | |
962 | |
963 /* setuid section ends */ | |
964 fprintf(stderr, "Cannot exec %s\n", APOPPASSWD); | |
965 fail(); | |
966 } | |
967 result = fdopen(toparent[0], "r"); | |
968 while (fgets(buf, BUFSIZ, result)) { | |
969 printf("%s<br>", buf); | |
970 fflush(stdout); | |
971 if (strstr(buf, "Success!")) { | |
972 printf("<br>Mail Password changed successfully!<br>\n"); | |
973 sc++; | |
974 break; | |
975 } else if (strstr(buf, "mismatch")) { | |
976 printf("二個入れた新パスワードが一致しません.<br>\n"); | |
977 break; | |
978 } else if (strstr(buf, "Illegal")) { | |
979 printf("照合用パスワードが違います.<br>--\n"); | |
980 break; | |
981 } else if (strstr(buf, "does not exist")) { | |
982 /* try_overwrite(user, pass, new, new2, suffix); */ | |
983 if (suffix[0]) { | |
984 printf("%s-%s", user, suffix); | |
985 } else { | |
986 printf("%s", user); | |
987 } | |
988 /* ここは来ないことになった(のはず) */ | |
989 printf("というメイルアカウントは未作成です<br>\n"); | |
990 printf("新規に作る場合はOKボタンをクリック\n"); | |
991 put_form(email, pass, new, new2, suffix, 1, 0, 1); | |
992 fflush(stdout); | |
993 } | |
994 } | |
995 fclose(result); | |
996 while (wait(0) != pid) {sleep(1);fputc('.', stderr);} | |
997 if (sc) success(email); else fail(); | |
998 } else if (user[0]) { | |
999 struct passwd *pw = getpwnam(user); | |
1000 int auth=0; | |
1001 if (!pw) { | |
1002 printf("そのようなユーザはいません %s<br>\n", user); | |
1003 fail(); | |
1004 } | |
1005 home=pw->pw_dir; | |
1006 | |
1007 printf("%s というメイルアドレスの<br>\n", email); | |
1008 printf("メイル専用パスワードを変更します.<br>\n"); | |
1009 printf("メイルパスワードとUNIXパスワードの違いに気をつけてください.<br>\n"); | |
1010 printf("新パスワードは8文字以上にしてください.<br>\n"); | |
1011 printf("New password must be more than or equal to 8 characters.<br>\n"); | |
1012 if (apopfile_existp(home, suffix, pw->pw_uid)) { | |
1013 auth = 0; /* this password file */ | |
1014 printf("「古いメイルパスワード」には、現在<br>\n"); | |
1015 printf("<tt>%s</tt><br>\n", email); | |
1016 printf("を読むために指定しているパスワードを入力します。"); | |
1017 } else if (apopfile_existp(home, "", pw->pw_uid)) { | |
1018 auth = 1; /* basic mail address password */ | |
1019 printf("今回は本人認証として基本メイルアドレスのパスワードを"); | |
1020 printf("入力しますが、新しくパスワードを設定するのは<br>\n"); | |
1021 printf("<tt>%s</tt><br>\n", email); | |
1022 printf("用のパスワードです。基本メイルアドレスのパスワードは"); | |
1023 printf("変わりませんので注意してください。"); | |
1024 } else { | |
1025 auth = 2; /* UNIX login */ | |
1026 } | |
1027 put_form(email, "", "", "", suffix, 0, auth, 0); | |
1028 footer(); | |
1029 exit(0); | |
1030 } | |
1031 printf("user=[%s]\n", user); | |
1032 } | |
1033 | |
1034 int main(int argc, char* argv[]) { | |
1035 char *method = getenv("REQUEST_METHOD"); | |
1036 char **args; | |
1037 myname = argv[0]; | |
1038 if (method && strcmp(method, "POST") != 0) { | |
1039 printf("This program should be used in method:POST.\n"); | |
1040 fail(); | |
1041 } | |
1042 printf("Content-type: text/html; charset=EUC-JP\n\n"); | |
1043 printf("<html>\n<head><title>Change Password</title></head>\n"); | |
1044 printf("<body style=\"background: #f0ffff;\">\n"); | |
1045 if (getenv("SSL_CIPHER") && getenv("SSL_PROTOCOL")) { | |
1046 args = decode_post(); | |
1047 apopcall(args); | |
1048 } else { | |
1049 printf("This program can be used only via SSL connection.<br>\n"); | |
1050 printf("このユーティリティはSSL接続時のみ有効です.<br>\n"); | |
1051 } | |
1052 } |