|
次のページ
前のページ
目次へ
8. Cプログラムを Shadow Suite に対応させる方法プログラムに shadow サポートを加えるのは実際にはとても簡単です。問題は
これは重大な問題です。SUID するプログラムを作る時には非常に慎重にプロ グラムする必要があります。例えば、シェルにエスケープできるプログラムは プログラムがrootに SUID されていてもrootとして実行してはなりません。 パスワードのチェックはするが、それ以外にはrootとして動作する必要がな いような場合で shadow サポートをプログラムに追加する時は shadow グルー プに SGID する方がずっと安全です。xlock プログラムはこのような例の典型 です。 以下で示す例の pppd-1.2.1d は既にrootに SUID されているので、shadow サ ポートを加えることで、プログラムがセキュリティ的により脆弱になることは もはやありません。 8.1 ヘッダファイルヘッダファイルは プログラムに shadow サポートを加えるためには次のヘッダファイルをインク ルードする必要があります: #include <shadow/shadow.h> #include <shadow/pwauth.h> shadow 用のコードを条件コンパイルで利用できるようにコンパイラ命令を用 いるのは良い考えです。(以下の例でもそうしています。) 8.2 libshadow.a ライブラリShadow Suite をインストールする時には プログラムで shadow サポートするためには、リンカに
これは以下のように行います:
しかし、以下の例でわかるように大規模なプログラムでは大抵
8.3 Shadow 構造体
struct spwd { char *sp_namp; /* login name */ char *sp_pwdp; /* encrypted password */ sptime sp_lstchg; /* date of last change */ sptime sp_min; /* minimum number of days between changes */ sptime sp_max; /* maximum number of days between changes */ sptime sp_warn; /* number of days of warning before password expires */ sptime sp_inact; /* number of days after password expires until the account becomes unusable. */ sptime sp_expire; /* days since 1/1/70 until account expires */ unsigned long sp_flag; /* reserved for future use */ }; Shadow Suite では
これで、パスワードに加えて これが意味するところは、2次認証に注意することと、実際の認証を行う時に
は関数 現在存在しているプログラムのほとんどがこれを行っていないため、 Shadow Suiteの作者は将来のバージョンではこの機能を無くすか仕 様を変更することを言っています。 8.4 Shadow サポートのための関数
extern void setspent __P ((void)); extern void endspent __P ((void)); extern struct spwd *sgetspent __P ((__const char *__string)); extern struct spwd *fgetspent __P ((FILE *__fp)); extern struct spwd *getspent __P ((void)); extern struct spwd *getspnam __P ((__const char *__name)); extern int putspent __P ((__const struct spwd *__sp, FILE *__fp)); これから例題で用いる関数は 8.5 例題これはデフォルトで shadow サポートをしていないプログラムを shadow 対応 させる例です。 この例では Point-to-Point プロトコルサーバ(pppd-1.2.1d) を用
いています。このプログラムは PAP や CHAP ファイルで
なく pppd のこの機能はあまり使わないものですが、Shadow Suite をイ
ンストールするとパスワードが
以下のコードはコード内の他の
#ifdef HAS_SHADOW #include <shadow.h> #include <shadow/pwauth.h> #endif 次の部分は実際のコードに対する変更点です。 変更前の
/* * login - Check the user name and password against the system * password database, and login the user if OK. * * returns: * UPAP_AUTHNAK: Login failed. * UPAP_AUTHACK: Login succeeded. * In either case, msg points to an appropriate message. */ static int login(user, passwd, msg, msglen) char *user; char *passwd; char **msg; int *msglen; { struct passwd *pw; char *epasswd; char *tty; if ((pw = getpwnam(user)) == NULL) { return (UPAP_AUTHNAK); } /* * XXX If no passwd, let them login without one. */ if (pw->pw_passwd == '\0') { return (UPAP_AUTHACK); } epasswd = crypt(passwd, pw->pw_passwd); if (strcmp(epasswd, pw->pw_passwd)) { return (UPAP_AUTHNAK); } syslog(LOG_INFO, "user %s logged in", user); /* * Write a wtmp entry for this user. */ tty = strrchr(devname, '/'); if (tty == NULL) tty = devname; else tty++; logwtmp(tty, user, ""); /* Add wtmp login entry */ logged_in = TRUE; return (UPAP_AUTHACK); } ユーザのパスワードは 次に、実際の認証を行うために関数 shadow をサポートするように変更した後の
/* * login - Check the user name and password against the system * password database, and login the user if OK. * * This function has been modified to support the Linux Shadow Password * Suite if USE_SHADOW is defined. * * returns: * UPAP_AUTHNAK: Login failed. * UPAP_AUTHACK: Login succeeded. * In either case, msg points to an appropriate message. */ static int login(user, passwd, msg, msglen) char *user; char *passwd; char **msg; int *msglen; { struct passwd *pw; char *epasswd; char *tty; #ifdef USE_SHADOW struct spwd *spwd; struct spwd *getspnam(); #endif if ((pw = getpwnam(user)) == NULL) { return (UPAP_AUTHNAK); } #ifdef USE_SHADOW spwd = getspnam(user); if (spwd) pw->pw_passwd = spwd->sp-pwdp; #endif /* * XXX If no passwd, let NOT them login without one. */ if (pw->pw_passwd == '\0') { return (UPAP_AUTHNAK); } #ifdef HAS_SHADOW if ((pw->pw_passwd && pw->pw_passwd[0] == '@' && pw_auth (pw->pw_passwd+1, pw->pw_name, PW_LOGIN, NULL)) || !valid (passwd, pw)) { return (UPAP_AUTHNAK); } #else epasswd = crypt(passwd, pw->pw_passwd); if (strcmp(epasswd, pw->pw_passwd)) { return (UPAP_AUTHNAK); } #endif syslog(LOG_INFO, "user %s logged in", user); /* * Write a wtmp entry for this user. */ tty = strrchr(devname, '/'); if (tty == NULL) tty = devname; else tty++; logwtmp(tty, user, ""); /* Add wtmp login entry */ logged_in = TRUE; return (UPAP_AUTHACK); } 注意深く調べれば、他にも変更点があることがわかります。オリジナルのバー
ジョンでは だから、もし元のバージョンをユーザ(例えば ppp)のシェルとして走らせると、
ユーザ パスワードが空の時には 面白いことに、 次に、以下の2点について Makefile を修正する必要があります:
Makefile を編集して、次の行を加えてください:
それから、次の行を見つけて:
以下のように変更してください:
最後に、コンパイル及びインストールを実行しましょう。 次のページ 前のページ 目次へ |
[ |