imapext-2007

view APOPtools/apopcall.c @ 1:28a55bc1110c

[mq]: imapext
author yuuji@gentei.org
date Mon, 14 Sep 2009 19:23:11 +0900
parents
children d741b3ecc917
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 }

UW-IMAP'd extensions by yuuji