/********************************************************************* usermod3-solaris.cc パスワード変更CGIです。 # g++ usermod3-solaris.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 #include #include // このあたりは適当に変えてください const unsigned int GID_STAFF = 10; const unsigned int GID_STUDENT = 600; using namespace std; map post; void parse_post() { while (true) { string s, t; int c; while ((c = getchar()) != EOF && c != '=') { s += char(c); } if (c == EOF) break; while ((c = getchar()) != EOF && c != '&') { if (c == '+') { t += ' '; } else if (c == '%') { int d = getchar(); int e = getchar(); 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; // Solaris doesn't like const int conv(int num_msg, /*const*/ struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { if (num_msg <= 0) return PAM_CONV_ERR; struct pam_response *r = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response)); 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 (strstr(msg[i]->msg, "New") != 0 || strstr(msg[i]->msg, "new") != 0) { r[i].resp = strdup(newpass); } else if (*oldpass != 0) { r[i].resp = strdup(oldpass); } else { r[i].resp = strdup(""); } } else { r[i].resp = strdup(""); } cout << (msg[i]->msg); for (int j = int(strlen(r[i].resp)); j > 0; j--) cout << '*'; cout << endl; } *resp = r; return PAM_SUCCESS; } const struct pam_conv conversation = { conv, NULL }; void changepass(string user, string oldpw, string newpw, bool endorsed = false) { struct passwd *pw = getpwnam(post["user"].c_str()); if (pw == 0) { // sleep(3); cout << "

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

このユーザのパスワード変更は管理人しかできません\n"; return; } if (pw->pw_gid != GID_STUDENT) { // sleep(3); cout << "

学生以外のパスワード変更は管理人しかできません\n"; return; } // setuid(0); // for solaris if (endorsed) { if (pw->pw_gid != GID_STUDENT) { cout << "

学生以外のパスワード変更は管理人しかできません\n"; return; } // setuid(0); // for solaris } pam_handle_t *pamh = 0; if (pam_start("passwd", post["user"].c_str(), &conversation, &pamh) != PAM_SUCCESS) { cout << "

原因不明のエラーです。管理者にご連絡ください\n"; return; } cout << "

\n";
    oldpass = oldpw.c_str();
    newpass = newpw.c_str();
    int retcode = PAM_SUCCESS;

    if (! endorsed) {
        retcode = pam_authenticate(pamh, 0);
        // 次の行でエラーを起こすなら消してください。
        cout << pam_strerror(pamh, retcode) << '\n';
    }

    if (retcode == PAM_SUCCESS) {
        // if (endorsed) setuid(0); // Linux
        setuid(0);              // Solaris
        retcode = pam_chauthtok(pamh, 0);
        // 次の行でエラーを起こすなら消してください。
        cout << pam_strerror(pamh, retcode) << '\n';
    }

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

パスワードを変更しました\n"; } else if (retcode == PAM_AUTHTOK_LOCK_BUSY) { cout << "

ただいま別の人がパスワード変更中のようです。再度お試しください。\n"; } else { cout << "

エラー! パスワードは変更できませんでした\n"; } } inline int irand(int n) { return int(n * (rand() / (RAND_MAX + 1.0))); } string randompass() { unsigned int seed = time(0) ^ getuid(); srand(seed); string s; for (int i = 0; i < 3; i++) s += "abcdefghijkmnpqrstuvwxyz"[irand(24)]; for (int i = 3; i < 8; i++) s += "0123456789"[irand(10)]; return s; } void endorse(string endorser, string pass, string user) { if (endorser.length() < 3 || endorser.length() > 32) { cout << "

保証人名の長さが変です\n"; return; } if (pass.length() < 3 || pass.length() > 32) { cout << "

保証人パスワードの長さが変です\n"; return; } struct passwd *pw = getpwnam(endorser.c_str()); if (pw == 0) { cout << "

そのような保証人はいません\n"; return; } if (pw->pw_gid != GID_STAFF) { cout << "

このユーザは保証人になれません\n"; return; } pam_handle_t *pamh = 0; if (pam_start("passwd", endorser.c_str(), &conversation, &pamh) != PAM_SUCCESS) { cout << "

原因不明のエラーです。管理者にご連絡ください\n"; return; } oldpass = pass.c_str(); newpass = ""; cout << "

\n";
    int retcode = pam_authenticate(pamh, 0);
    // 次の行でエラーを起こすなら消してください。
    cout << pam_strerror(pamh, retcode) << '\n';
    pam_end(pamh, 0);
    cout << "
\n"; if (retcode != PAM_SUCCESS) { cout << "

保証人パスワードが認証できませんでした\n"; return; } cout << "

保証人の認証に成功しました\n"; syslog(LOG_ERR, "%s authenticated", endorser.c_str()); string newpw = randompass(); cout << "

新しいパスワード " << newpw << " を設定します。メモっておいてください。\n"; changepass(user, "", newpw, true); } int main() { cout << "Content-type: text/html\n\n" "\n" "\n" "\n" "\n" "\n" "\n" "usermod.cgi\n" "\n" "

パスワード変更

\n"; parse_post(); openlog("usermod.cgi", LOG_PID, 0); if (post["user"].length() < 3 || post["user"].length() > 32) { cout << "

ユーザ名の長さが変です\n"; } else if (! post["endorser"].empty()) { endorse(post["endorser"], post["endopass"], post["user"]); } else if (post["newpass1"] != post["newpass2"]) { cout << "

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

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

新旧パスワードが同じです"; } else if (post["oldpass"].length() > 32) { cout << "

旧パスワードの長さが変です\n"; } else { changepass(post["user"], post["oldpass"], post["newpass1"]); } closelog(); }