/********************************************************************* forward2.cc メール回送設定CGIのPAM版です。 ご自由にお使い下さい。 g++ -Wall forward2.cc -o forward.cgi -lpam のようにしてコンパイルし,suid root して使います。 詳しくは http://www.matsusaka-u.ac.jp/~okumura/cplusplus/forward.html をご覧ください。 Haruhiko Okumura *********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include using namespace std; map post; int uid; int gid; char* homedir; const char *pass; int conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { struct pam_response *r = (pam_response *) malloc(sizeof(struct pam_response) * num_msg); if (num_msg <= 0) return PAM_CONV_ERR; if (r == 0) return PAM_CONV_ERR; for (int i = 0; i < num_msg; i++) { r[i].resp_retcode = 0; // currently unused, zero expected if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) { r[i].resp = strdup(pass); } else { r[i].resp = strdup(""); } cout << (msg[i]->msg); for (int j = 0; j < int(strlen(r[i].resp)); j++) cout << '*'; cout << endl; } *resp = r; return PAM_SUCCESS; } /** ユーザ名 user, パスワード pass を検証する。 スーパーユーザでなければならない。 */ bool auth_user(const char *user) { struct passwd *pw; /* passwd entry */ /* look for the user in the password file */ /* need not be a superuser */ if ((pw = getpwnam(user)) == NULL) { /* Not listed in passwd */ /* sleep(3); */ return false; } uid = pw->pw_uid; gid = pw->pw_gid; homedir = pw->pw_dir; return true; } void parse_post() { while (cin) { string s, t; int c; while ((c = cin.get()) != EOF && c != '=') { s += char(c); } if (c == EOF) break; while ((c = cin.get()) != EOF && c != '&') { if (c == '+') { t += ' '; } else if (c == '%') { int d = cin.get(); int e = cin.get(); d = (d >= 'A') ? (d & 0xdf) - 'A' + 10 : d - '0'; e = (e >= 'A') ? (e & 0xdf) - 'A' + 10 : e - '0'; if (d >= 0 && d < 16 && e >= 0 && e < 16) { t += char(16 * d + e); } else { t += char(c); t += char(d); t += char(e); } } else { t += char(c); } } post[s] = t; } } bool checkaddr(string s) { int atcount = 0; for (string::const_iterator p = s.begin(); p != s.end(); ++p) { if (*p == '@') { atcount++; } else if (*p >= 'a' && *p <= 'z') { // good } else if (*p >= 'A' && *p <= 'Z') { // good } else if (*p >= '0' && *p <= '9') { // good } else if (*p == '.' || *p == '_' || *p == '-') { // good } else { return false; } } if (atcount == 0 || atcount > 1) return false; return true; } const struct pam_conv conversation = { conv, NULL }; int main() { pam_handle_t *pamh = 0; cout << "Content-type: text/html\n\n" "\n" "\n" "\n" "\n" "\n" "\n" "メール回送設定\n" "\n" "

メール回送設定

\n"; parse_post(); pass = post["pass"].c_str(); if (post["user"].length() < 3 || post["user"].length() > 32) { cout << "

ユーザ名の長さが変です\n"; } else if (pam_start("passwd", post["user"].c_str(), &conversation, &pamh) != PAM_SUCCESS) { cout << "

原因不明のエラーです。管理者にご連絡ください\n"; } else if (post["pass"].length() < 3) { cout << "

パスワードの長さが変です\n"; } else if (!post["email"].empty() && !checkaddr(post["email"])) { cout << "

メールアドレスが不正です\n"; } else if (!auth_user(post["user"].c_str())) { sleep(3); cout << "

ユーザ名が不正です\n"; } else if (pam_authenticate(pamh, 0) != PAM_SUCCESS) { sleep(3); cout << "

パスワードが不正です"; } else { string path = string(homedir) + "/.forward"; if (post["email"].length() != 0) { ofstream out(path.c_str()); if (!out) { cout << ".forward が開きません"; } else { if (post["keep"] == string("on")) out << '\\' << post["user"] << ", "; out << post["email"] << '\n'; out.close(); chown(path.c_str(), uid, gid); cout << "

設定しました"; } } else { remove(path.c_str()); cout << "

設定しました"; } } if (pamh != 0) pam_end(pamh, 0); }