imapext-2007

view APOPtools/apopcall.c @ 4:d741b3ecc917

imapext-2007f
author HIROSE Yuuji <yuuji@gentei.org>
date Thu, 30 Oct 2014 00:03:05 +0900
parents 28a55bc1110c
children
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/wait.h>
7 #include <sys/stat.h>
8 #include <pwd.h>
9 #ifdef SHADOW_PASSWD
10 #include <shadow.h>
11 #endif
13 #ifndef APOPPASSWD
14 #define APOPPASSWD "/usr/local/bin/apoppasswd"
15 #endif
16 #ifndef APOPFILEBASE
17 #define APOPFILEBASE ".apop"
18 #endif
19 #ifndef XADDR_DELIM
20 #define XADDR_DELIM ('-')
21 #endif
23 char *myname;
25 int ishexa(int c) {
26 strchr("0123456789ABCDFabcdef", c) ? 1 : 0;
27 }
29 put_form(email, pass, new, new2, suffix, hidden, auth, force)
30 char *email, *pass, *new, *new2, *suffix;
31 int hidden, auth, force;
32 /* auth = 0: old password
33 1: base addresse's mail password
34 2: unix password */
35 {
36 char *authtype[] = {"old", "base", "unix"};
37 char *var[] = {"email", "pass", "new", "new2", "auth", ""};
38 char *val[] = {email, pass, new, new2, authtype[auth]};
39 char *prm[] = {"", /* "ユーザ名", */
40 auth ?
41 ((auth==1)
42 ? "基本メイルアドレス用パスワード<br>Password for Basic Mail address"
43 : "UNIXログインパスワード<br>UNIX login Password")
44 : "古いメイルパスワード<br>Old Mail Password",
45 "新しいメイルパスワード<br>New Mail Password",
46 "新パスワードをもう一回(確認)<br>New Mail Password Again",
47 ""};
48 int h=0, i;
50 printf("<form method=POST action\"./%s\">\n", myname);
51 printf(" <table border=1>\n");
52 for (i=0; var[i][0]; i++) {
53 h = hidden || strstr("email,suffix,auth", var[i]);
54 if (prm[i][0]) {
55 printf("<tr><td>%s</td><td>", prm[i]);
56 } else {
57 }
58 printf("<input name=%s %svalue=\"%s\" length=40 maxlength=40>\n",
59 var[i],
60 h ? "type=hidden "
61 : (strstr(prm[i], "パスワード") ? "type=password " : "<br>"),
62 val[i]);
63 if (!strcmp(var[i], "suffix")) {
64 /* ここでは suffix を入れさせない方がいいかも */
65 /* 表向きのメイルアドレスを表示しておく */
66 printf("%s", email);
67 /* if (suffix[0]) {
68 printf("-%s", suffix);
69 } */
70 if (auth)
71 printf("<br>(新規作成:New Account)");
72 }
73 if (prm[i][0])
74 printf("</td></tr>");
75 printf("\n");
76 }
78 printf("</table>\n");
79 if (force)
80 printf("<input name=force type=hidden value=ON>\n");
81 if (auth) {
82 char *a[] = {"basic", "unix"};
83 printf("<input type=hidden name=auth value=\"%s\">\n", a[auth-1]);
84 }
85 printf("<input name=OK value=OK type=submit>\n");
86 printf("<input name=RESET value=RESET type=reset>\n");
87 printf("</form>\n");
88 fflush(stdout);
89 }
91 char *decode(char *code) {
92 int l=1+strlen(code);
93 int i, c, d;
94 char *ret = (char*)malloc(l*sizeof(char));
95 char *p = code;
96 memset(ret, 0, l);
97 for (i=0; i<strlen(code); i++) {
98 if (code[i] == '+') code[i] = ' ';
99 }
100 while (code[0] && (p=strchr(code, '%'))
101 && ishexa(*(p+1)) && ishexa(*(p+2))) {
102 *(p++) = '\0';
103 strncat(ret, code, l);
104 c = (islower(*p) ? toupper(*p) : *p) - '0';
105 p++;
106 d = (islower(*p) ? toupper(*p) : *p) - '0';
107 if (c > 9) c -= ('A'-'9'-1);
108 if (d > 9) d -= ('A'-'9'-1);
109 ret[strlen(ret)] = c*16+d;
110 code = p+1;
111 }
112 if (code[0]) strncat(ret, code, l);
113 return ret;
114 }
116 #define BSIZE 8192
117 char **decode_post() {
118 char *buf = (char*)malloc(BSIZE*sizeof(char));
119 char **post, *p = buf;
120 int n=0, i;
121 post = (char**)calloc(1, sizeof(char*));
122 *buf = '\0';
123 fgets(buf, BSIZE, stdin);
124 if (strchr("\n\r", buf[strlen(buf)-1])) /* chop */
125 buf[strlen(buf)-1] = '\0';
126 while (buf[0] && NULL != (p=strchr(buf, '&'))) {
127 *p = '\0';
128 post[n] = (char*)malloc((p-buf+1)*sizeof(char));
129 strcpy(post[n], buf);
130 n++;
131 post = (char**)realloc(post, (1+n)*sizeof(char*));
132 buf = 1+p;
133 }
134 if (buf[0]) post[n++] = buf;
135 /* decode URL encoded */
136 for (i=0; i < n; i++) {
137 char *p;
138 p=post[i];
139 post[i] = decode(p);
140 }
141 post[i] = ""; /* terminator */
142 return post;
143 }
145 void footer() {
146 puts("</body>\n</html>");
147 fflush(stdout);
148 }
150 void fail() {
151 printf("パスワード更新に失敗しました<br>\n");
152 printf("<a href=\"./\">やり直し</a><br>\n");
153 footer();
154 exit(1);
155 }
156 void success(char *email) {
157 printf("<hr>メイルアカウント %s 用のパスワード更新は完了しました。<br>\n",
158 email);
159 footer();
160 exit(0);
161 }
163 int apopfile_existp(char *home, char *suffix, uid_t uid) {
164 struct stat st;
165 int s;
166 int len = strlen(home) + 1
167 + strlen(APOPFILEBASE) + strlen(suffix) + 3;
168 char *apopfile = (char*)malloc(len);
169 if (suffix[0]) {
170 snprintf(apopfile, len, "%s/%s%c%s%c",
171 home, APOPFILEBASE, XADDR_DELIM, suffix, 0);
172 } else {
173 snprintf(apopfile, len, "%s/%s%c", home, APOPFILEBASE, 0);
174 }
175 seteuid(uid);
176 s = stat(apopfile, &st);
177 seteuid(0);
178 memset(apopfile, '\0', strlen(apopfile));
179 free(apopfile);
180 return !s;
181 }
183 #ifndef QMAILCONTROL
184 # define QMAILCONTROL "/var/qmail/control"
185 #endif
186 #ifndef MAILTMPLEN
187 # define MAILTMPLEN 1024
188 #endif
190 /* Convert virtual domain user
191 */
192 char* conv_virtualdomain(char *account) {
193 char *dom = strchr(account, '@'), *p;
194 char vd[MAILTMPLEN+1], rewrite[MAILTMPLEN+1], previous[MAILTMPLEN+1];
195 FILE *vdfd;
196 int match=0;
197 char buf[MAILTMPLEN+1], *s;
198 snprintf(vd, MAILTMPLEN, "%s/%s", QMAILCONTROL, "virtualdomains");
199 if (NULL == dom) return account;
200 dom++; /* set position of domain part beginning */
201 if (dom && NULL != (vdfd = fopen (vd, "r"))) {
202 int l = strlen(dom);
203 int L = strlen(account);
204 while ((s=fgets(buf, MAILTMPLEN, vdfd))) {
205 if (p=strchr(s, '#'))
206 *p = '\0'; /* zap comments */
207 if (!strchr(buf, ':'))
208 continue;
209 while (s && (strrchr(s, '\n') || strrchr(s, '\r') || strrchr(s, ' ')))
210 s[strlen(s)-1] = '\0';
211 if (!strncmp(account, s, L) && s[L] == ':' && s[L+1]) { /* user matches */
212 match = 3;
213 snprintf(rewrite, MAILTMPLEN, "%s-%s", s+L+1, account);
214 break;
215 }
216 if (!strncmp(dom, s, l) && s[l] == ':' && s[l+1]) { /* domain matches */
217 match = 2;
218 snprintf(rewrite, MAILTMPLEN, "%s%c%s", s+l+1, XADDR_DELIM, account);
219 continue;
220 }
221 if (match < 2 && s[0] == '.') { /* if domain described in wildcard */
222 if (p=strchr(s, ':')) {
223 *p = '\0';
224 if (!strcmp(dom+(strlen(dom)-strlen(s)), s)) {
225 if (match == 0
226 || strlen(previous) < strlen(s)) {
227 match = 1;
228 strncpy(previous, s, MAILTMPLEN);
229 snprintf(rewrite, MAILTMPLEN, "%s%c%s", p+1, XADDR_DELIM, account);
230 }
231 }
232 }
233 }
234 }
235 fclose(vdfd);
236 if (match) {
237 p = strchr(rewrite, '@');
238 /* fprintf(stderr, "m=%d, rwr=[%s]\n", match, rewrite); */
239 if (p) {
240 *p = '\0';
241 }
242 /* fprintf(stderr, "rwr=[%s]\n", rewrite); */
243 s = malloc(strlen(rewrite)+1);
244 strncpy(s, rewrite, strlen(rewrite)+1);
245 memset(vd, 0, sizeof(vd));
246 memset(rewrite, 0, sizeof(rewrite));
247 memset(previous, 0, sizeof(previous));
248 return s;
249 }
250 }
251 /* Then, compare with locals */
252 snprintf(vd, MAILTMPLEN, "%s/%s", QMAILCONTROL, "locals");
253 if (NULL != (vdfd=fopen(vd, "r"))) {
254 while (s=fgets(buf, MAILTMPLEN, vdfd)) {
255 if (p=strchr(s, '#')) *p = '\0'; /* zap after comment mark # */
256 while (*s && (strrchr(s, '\r')||strrchr(s, '\n')
257 ||strrchr(s, ' ')||strrchr(s, '\t'))) {
258 *(s+strlen(s)-1) = '\0';
259 }
260 while (*s && (*s == '\t' || *s == ' ')) s++;
261 if (!strncmp(s, dom, strlen(s))) { /* matches with local domain */
262 int len = dom-account-1;
263 p = (char*)malloc(len+1);
264 memset(p, '\0', len+1);
265 strncpy(p, account, len);
266 return p;
267 }
268 }
269 }
270 return NULL; /* invalid domain */
271 /* return account; return itself */
272 }
274 void apopcall(char **args) {
275 int i=0, sc=0;
276 pid_t pid;
277 char *email="", *suffix="", *pass="", *new="", *new2 = "", *home="";
278 char buf[BUFSIZ], auth, *user;
279 FILE *child, *result;
280 while (args[i][0]) {
281 /* printf("[%s]<br>\n", args[i]); */
282 if (!strncmp("email=", args[i], 6)) {
283 email = args[i]+6;
284 } else if (!strncmp("suffix=", args[i], 7)) {
285 suffix = args[i]+7;
286 } else if (!strncmp("pass=", args[i], 5)) {
287 pass = args[i]+5;
288 } else if (!strncmp("new=", args[i], 4)) {
289 new = args[i]+4;
290 } else if (!strncmp("new2=", args[i], 5)) {
291 new2 = args[i]+5;
292 } else if (!strncmp("auth=", args[i], 5)) {
293 /* "this" or "base" or "unix" */
294 auth = args[i][5];
295 }
296 i++;
297 }
298 /* Make a backup of original e-mail address */
299 /* user = (char*)malloc(1+strlen(email));
300 strcpy(user, email);
301 */
302 user = conv_virtualdomain(email);
303 if (NULL == user) {
304 printf("そのようなドメインは無効です(%s)<br>\n", strchr(email, '@'));
305 printf("入力したメイルアドレスを確認してやり直してください.<br>\n");
306 fail();
307 }
308 if (strchr(user, XADDR_DELIM)) {
309 char *p = malloc(1+strlen(user));
310 char *q = NULL;
311 struct passwd *pwd;
312 /* printf("user=[%s]<br>\n", user); */
314 memset(p, '\0', 1+strlen(user));
315 strcpy(p, user);
316 while (!(pwd=getpwnam(p)) && (q=strrchr(p, XADDR_DELIM))) {
317 fflush(stdout);
318 *q = '\0';
319 }
320 if (pwd && q) {
321 q = user+(q-p)+1;
322 user=p;
323 suffix=q;
324 }
325 }
326 if (user[0] && new[0] && new2[0]) {
327 int tochild[2], toparent[2];
328 pid_t pid;
329 int argc=0;
330 char **argv;
331 struct passwd *pswd;
332 char *pstr;
334 if (!(pswd=getpwnam(user))) {
335 printf("Unkown user %s.\n", user);
336 fflush(stdout);
337 fail();
338 }
339 pstr = pswd->pw_passwd;
340 #ifdef SHADOW_PASSWD
341 { struct spwd *ss = getspnam(user);
342 pstr = (char*)ss->sp_pwdp;
343 }
344 #endif
345 home=pswd->pw_dir;
346 argv = (char**)calloc(4, sizeof(char*));
347 argv[argc++] = "apoppasswd";
348 argv[argc++] = "-s";
349 argv[argc++] = "-c";
350 /* if old password does not exist,
351 then check UNIX password */
352 #if 0
353 if (apopfile_existp(home, suffix, pswd->pw_uid)) { /* no apop-ext exists */
354 /* そのまま */
355 } else if (apopfile_existp(home, "", pswd->pw_uid)) {/* check base mail password */
356 argv = (char**)realloc(argv, (argc+2)*sizeof(char*));
357 argv[argc++] = "-b";
358 }
359 #endif
360 switch (auth) {
361 case 'b': case 'B':
362 if (apopfile_existp(home, "", pswd->pw_uid)) {
363 argv = (char**)realloc(argv, (argc+2)*sizeof(char*));
364 argv[argc++] = "-b";
365 } else {
366 printf("基本アドレスのパスワードファイルがありません<br>\n");
367 fail();
368 }
369 break;
370 case 'u': case 'U':
371 if (strcmp(pstr, (char*)crypt(pass, pstr))) {
372 printf("UNIX Password not correct.<br>\n");
373 /* printf("[%s]vs.[%s]<br>\n",
374 pswd->pw_passwd, crypt(pass, pswd->pw_passwd)); */
375 printf("UNIXパスワードと一致しません.<br>\n");
376 fflush(stdout);
377 fail();
378 }
379 }
381 if (strlen(new) < 8 || strlen(new2) < 8) {
382 printf("New mail password must be more than 7 characters.<br>\n");
383 printf("メイルパスワードは8文字以上にしてください。<br>\n");
384 fflush(stdout);
385 fail();
386 }
387 if (suffix[0]) {
388 argv = (char**)realloc(argv, (argc+3)*sizeof(char*));
389 argv[argc++] = "-e";
390 argv[argc++] = suffix;
392 }
393 argv[argc++] = NULL;
394 if (setgid(pswd->pw_gid) || 0 != setuid(pswd->pw_uid)) {
395 printf("Cannot switch to %s\n", user);
396 printf("uid=%d, gid=%d<br>\n", pswd->pw_gid, pswd->pw_uid);
397 printf("メイルパスワード変更サーバの設定不良の可能性があるので<br>\n");
398 printf("お手数ですがこの画面のコピーを添えてシステム管理者");
399 printf("まで御連絡下さい。<br>\n");
400 fflush(stdout);
401 fail();
402 }
404 /* OK, start apopasswd */
405 if (pipe(tochild)+pipe(toparent)) {
406 printf("Cannot create pipe\n");
407 fail();
408 }
409 if ((pid=fork()) > 0) {
410 FILE *child = fdopen(tochild[1], "w");
411 close(tochild[0]);
412 close(toparent[1]);
413 fprintf(child, "PASS %s\nNEW %s\nNEW2 %s\n",
414 pass, new, new2);
415 fflush(child);
416 fclose(child);
418 } else if (pid == -1) {
419 printf("Cannot fork\n");
420 fail();
421 } else {
422 char *pe = malloc(6+strlen(pswd->pw_dir));
423 close(tochild[1]);
424 close(toparent[0]);
425 dup2(tochild[0], 0);
426 dup2(toparent[1], 1);
428 /* setuid section */
430 strcpy(pe, "HOME=");
431 strcat(pe, pswd->pw_dir);
432 if (putenv(pe)) {
433 puts("ga-n! arichan gakkari<br>");
434 }
435 execv(APOPPASSWD, argv);
437 /* setuid section ends */
438 fprintf(stderr, "Cannot exec %s\n", APOPPASSWD);
439 fail();
440 }
441 result = fdopen(toparent[0], "r");
442 while (fgets(buf, BUFSIZ, result)) {
443 printf("%s<br>", buf);
444 fflush(stdout);
445 if (strstr(buf, "Success!")) {
446 printf("<br>Mail Password changed successfully!<br>\n");
447 sc++;
448 break;
449 } else if (strstr(buf, "mismatch")) {
450 printf("二個入れた新パスワードが一致しません.<br>\n");
451 break;
452 } else if (strstr(buf, "Illegal")) {
453 printf("照合用パスワードが違います.<br>--\n");
454 break;
455 } else if (strstr(buf, "does not exist")) {
456 /* try_overwrite(user, pass, new, new2, suffix); */
457 if (suffix[0]) {
458 printf("%s-%s", user, suffix);
459 } else {
460 printf("%s", user);
461 }
462 /* ここは来ないことになった(のはず) */
463 printf("というメイルアカウントは未作成です<br>\n");
464 printf("新規に作る場合はOKボタンをクリック\n");
465 put_form(email, pass, new, new2, suffix, 1, 0, 1);
466 fflush(stdout);
467 }
468 }
469 fclose(result);
470 while (wait(0) != pid) {sleep(1);fputc('.', stderr);}
471 if (sc) success(email); else fail();
472 } else if (user[0]) {
473 struct passwd *pw = getpwnam(user);
474 int auth=0;
475 if (!pw) {
476 printf("そのようなユーザはいません %s<br>\n", user);
477 fail();
478 }
479 home=pw->pw_dir;
481 printf("%s というメイルアドレスの<br>\n", email);
482 printf("メイル専用パスワードを変更します.<br>\n");
483 printf("メイルパスワードとUNIXパスワードの違いに気をつけてください.<br>\n");
484 printf("新パスワードは8文字以上にしてください.<br>\n");
485 printf("New password must be more than or equal to 8 characters.<br>\n");
486 if (apopfile_existp(home, suffix, pw->pw_uid)) {
487 auth = 0; /* this password file */
488 printf("「古いメイルパスワード」には、現在<br>\n");
489 printf("<tt>%s</tt><br>\n", email);
490 printf("を読むために指定しているパスワードを入力します。");
491 } else if (apopfile_existp(home, "", pw->pw_uid)) {
492 auth = 1; /* basic mail address password */
493 printf("今回は本人認証として基本メイルアドレスのパスワードを");
494 printf("入力しますが、新しくパスワードを設定するのは<br>\n");
495 printf("<tt>%s</tt><br>\n", email);
496 printf("用のパスワードです。基本メイルアドレスのパスワードは");
497 printf("変わりませんので注意してください。");
498 } else {
499 auth = 2; /* UNIX login */
500 }
501 put_form(email, "", "", "", suffix, 0, auth, 0);
502 footer();
503 exit(0);
504 }
505 printf("user=[%s]\n", user);
506 }
508 int main(int argc, char* argv[]) {
509 char *method = getenv("REQUEST_METHOD");
510 char **args;
511 myname = argv[0];
512 if (method && strcmp(method, "POST") != 0) {
513 printf("This program should be used in method:POST.\n");
514 fail();
515 }
516 printf("Content-type: text/html; charset=EUC-JP\n\n");
517 printf("<html>\n<head><title>Change Password</title></head>\n");
518 printf("<body style=\"background: #f0ffff;\">\n");
519 if (getenv("SSL_CIPHER") && getenv("SSL_PROTOCOL")) {
520 args = decode_post();
521 apopcall(args);
522 } else {
523 printf("This program can be used only via SSL connection.<br>\n");
524 printf("このユーティリティはSSL接続時のみ有効です.<br>\n");
525 }
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
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
549 char *myname;
551 int ishexa(int c) {
552 strchr("0123456789ABCDFabcdef", c) ? 1 : 0;
553 }
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;
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 }
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 }
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 }
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 }
671 void footer() {
672 puts("</body>\n</html>");
673 fflush(stdout);
674 }
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 }
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 }
709 #ifndef QMAILCONTROL
710 # define QMAILCONTROL "/var/qmail/control"
711 #endif
712 #ifndef MAILTMPLEN
713 # define MAILTMPLEN 1024
714 #endif
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 }
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); */
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;
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 }
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;
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 }
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);
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);
954 /* setuid section */
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);
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();
1005 home=pw->pw_dir;
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 */
1027 put_form(email, "", "", "", suffix, 0, auth, 0);
1028 footer();
1029 exit(0);
1031 printf("user=[%s]\n", user);
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();
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");

UW-IMAP'd extensions by yuuji