/********************************************************************* usermod2.cc パスワード変更CGIです。 PAMを使っていますのでmd5パスワードでも大丈夫なはずです。 # g++ usermod2.cc -o usermod.cgi -lpam # chmod 4511 usermod.cgi のようにしてコンパイルします。 詳しくは http://www.matsusaka-u.ac.jp/~okumura/cplusplus/passwd.html をご覧ください。 Haruhiko Okumura *********************************************************************/ #include #include #include #include #include #include #include #include #include #include using namespace std; map post; 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; } } const char *oldpass, *newpass; int conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { static int state = 0; 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) { if (state++ == 0) r[i].resp = strdup(oldpass); else r[i].resp = strdup(newpass); } 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; } 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" "usermod.cgi\n" "\n" "

パスワード変更

\n"; parse_post(); 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["oldpass"].length() < 3 || post["oldpass"].length() > 32) { cout << "

旧パスワードの長さが変です\n"; } else if (post["newpass1"] != post["newpass2"]) { cout << "

二つの新パスワードが一致しません\n"; } else if (post["newpass1"].length() < 3 || post["newpass1"].length() > 32) { cout << "

新パスワードの長さが変です\n"; } else if (post["oldpass"] == post["newpass1"]) { cout << "

新旧パスワードが同じです"; } else { oldpass = post["oldpass"].c_str(); newpass = post["newpass1"].c_str(); // パスワードの確認だけなら次のようにする // if (pam_authenticate(pamh, 0) != PAM_SUCCESS) { // sleep(3); // cout << "

旧パスワードが不正です\n"; // } struct passwd *pw = getpwnam(post["user"].c_str()); if (pw == 0) { sleep(3); cout << "

そのような利用者はいません\n"; } else if (pw->pw_uid < 100) { sleep(3); cout << "

このユーザのパスワード変更は管理人しかできません\n"; // pw->pw_gid で gid もわかる } else { cout << "

\n";
            int retcode = pam_chauthtok(pamh, 0);
            cout << "
\n"; if (retcode == PAM_SUCCESS) { cout << "

パスワードを変更しました\n"; } else { sleep(3); cout << "

エラー! パスワードは変更できませんでした\n"; } } } if (pamh != 0) pam_end(pamh, 0); }