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 }

yatex.org