00001
00002
00003
00004
00005
00006
00007
00008 #include "wvlog.h"
00009 #include "wvpam.h"
00010 #include "wvautoconf.h"
00011
00012
00013 #ifndef HAVE_SECURITY_PAM_APPL_H
00014
00015 WvPam::WvPam(WvStringParm _appname)
00016 : log("PAM Auth", WvLog::Info), appname(_appname)
00017 {
00018 err.seterr("Compiled without PAM Support!\n");
00019 }
00020
00021
00022 WvPam::WvPam(WvStringParm _appname, WvStringParm rhost,
00023 WvStringParm user, WvStringParm password)
00024 : log("PAM Auth", WvLog::Info), appname(_appname)
00025 {
00026 err.seterr("Compiled without PAM Support!\n");
00027 }
00028
00029
00030 WvPam::~WvPam()
00031 {
00032 }
00033
00034 bool WvPam::authenticate(WvStringParm rhost, WvStringParm user, WvStringParm password)
00035 {
00036 return false;
00037 }
00038
00039 WvString WvPam::getuser() const
00040 {
00041 return WvString::null;
00042 }
00043
00044
00045 void WvPam::getgroups(WvStringList &l) const
00046 {
00047 }
00048
00049 #else // HAVE_SECURITY_PAM_APPL_H
00050
00051 #include <security/pam_appl.h>
00052 #include <sys/types.h>
00053 #include <pwd.h>
00054 #include <grp.h>
00055
00056 #include "wvaddr.h"
00057
00058
00059 class WvPamData
00060 {
00061 public:
00062 pam_handle_t *pamh;
00063 int status;
00064 WvString failmsg, user;
00065 WvStringList groups;
00066
00067 WvPamData()
00068 : pamh(NULL), status(PAM_SUCCESS), user("")
00069 { }
00070
00071 WvPamData(WvStringParm _failmsg)
00072 : pamh(NULL), status(PAM_SUCCESS), failmsg(_failmsg)
00073 { }
00074 };
00075
00076
00078 #if HAVE_BROKEN_PAM
00079 int noconv(int num_msg, struct pam_message **msgm,
00080 struct pam_response **response, void *userdata)
00081 #else
00082 int noconv(int num_msg, const struct pam_message **msgm,
00083 struct pam_response **response, void *userdata)
00084 #endif
00085 {
00086
00087 return PAM_CONV_ERR;
00088 }
00089
00090
00091
00092
00093
00094 #if HAVE_BROKEN_PAM
00095 static int passconv(int num_msg, struct pam_message **msgm,
00096 struct pam_response **response, void *userdata)
00097 #else
00098 static int passconv(int num_msg, const struct pam_message **msgm,
00099 struct pam_response **response, void *userdata)
00100 #endif
00101 {
00102 struct pam_response *password_echo;
00103
00104 password_echo = (struct pam_response *)calloc(num_msg,
00105 sizeof(struct pam_response));
00106 password_echo->resp = (char *)userdata;
00107 password_echo->resp_retcode = 0;
00108
00109 *response = password_echo;
00110
00111 return PAM_SUCCESS;
00112 }
00113
00114 WvPam::WvPam(WvStringParm _appname)
00115 : log("PAM Auth", WvLog::Info), appname(_appname)
00116 {
00117 init();
00118 }
00119
00120
00121 WvPam::WvPam(WvStringParm _appname, WvStringParm rhost,
00122 WvStringParm user, WvStringParm password)
00123 : log("PAM Auth", WvLog::Info), appname(_appname)
00124 {
00125 if (init())
00126 authenticate(rhost, user, password);
00127 }
00128
00129 WvPam::~WvPam()
00130 {
00131 log(WvLog::Debug2, "Shutting down PAM Session for: %s\n", appname);
00132 if (d->status == PAM_SUCCESS)
00133 pam_close_session(d->pamh, 0);
00134 pam_end(d->pamh, d->status);
00135 d->groups.zap();
00136 delete d;
00137 }
00138
00139
00140 bool WvPam::init()
00141 {
00142 d = new WvPamData();
00143 log(WvLog::Debug2, "Starting up PAM Session for: %s\n", appname);
00144 err.seterr("Not yet authenticated...");
00145
00146 struct pam_conv c;
00147 c.conv = noconv;
00148 c.appdata_ptr = NULL;
00149
00150 d->pamh = NULL;
00151 d->status = pam_start(appname, d->user, &c, &d->pamh);
00152 if (check_pam_status("pam_start")) return true;
00153 return false;
00154 }
00155
00156 bool WvPam::authenticate(WvStringParm rhost, WvStringParm user, WvStringParm password)
00157 {
00158
00159 assert(d);
00160
00161 if (!!rhost)
00162 {
00163 d->status = pam_set_item(d->pamh, PAM_RHOST, rhost);
00164 if (!check_pam_status("rhost setup"))
00165 return false;
00166 }
00167
00168 if (!!user)
00169 {
00170 d->user = user;
00171 d->status = pam_set_item(d->pamh, PAM_USER, user);
00172 if (!check_pam_status("user setup"))
00173 return false;
00174 }
00175
00176 if (!!password)
00177 {
00178 struct pam_conv c;
00179 c.conv = passconv;
00180 c.appdata_ptr = strdup(password);
00181 d->status = pam_set_item(d->pamh, PAM_CONV, &c);
00182 if (!check_pam_status("conversation setup"))
00183 return false;
00184
00185 d->status = pam_set_item(d->pamh, PAM_AUTHTOK, password);
00186 if (!check_pam_status("password setup"))
00187 return false;
00188 }
00189
00190 #if HAVE_BROKEN_PAM
00191 void *x = NULL;
00192 #else
00193 const void *x = NULL;
00194 #endif
00195 d->status = pam_get_item(d->pamh, PAM_USER, &x);
00196 if (!check_pam_status("get username"))
00197 return false;
00198 d->user = (const char *)x;
00199 d->user.unique();
00200
00201 log("Starting Authentication for %s@%s\n", d->user, rhost);
00202
00203 d->status = pam_authenticate(d->pamh, PAM_DISALLOW_NULL_AUTHTOK | PAM_SILENT);
00204 if (!check_pam_status("authentication")) return false;
00205
00206 d->status = pam_acct_mgmt(d->pamh, PAM_DISALLOW_NULL_AUTHTOK | PAM_SILENT);
00207 if (!check_pam_status("account management")) return false;
00208
00209 d->status = pam_setcred(d->pamh, PAM_ESTABLISH_CRED);
00210 if (!check_pam_status("credentials")) return false;
00211
00212 d->status = pam_open_session(d->pamh, 0);
00213 if (!check_pam_status("session open")) return false;
00214
00215
00216 if (!d->user)
00217 {
00218 const void *x = NULL;
00219 d->status = pam_get_item(d->pamh, PAM_USER, &x);
00220 if (!check_pam_status("get username")) return false;
00221 d->user = (const char *)x;
00222 d->user.unique();
00223 }
00224 log("Session open as user '%s'\n", d->user);
00225
00226
00227
00228 err.noerr();
00229
00230 return true;
00231 }
00232
00233
00234 bool WvPam::check_pam_status(WvStringParm s)
00235 {
00236 if (d->status == PAM_SUCCESS)
00237 {
00238 log(WvLog::Debug2, "PAM %s succeeded.\n", s);
00239 return true;
00240 }
00241 else
00242 {
00243 WvString msg("PAM %s failed: %s\n", s, pam_strerror(d->pamh, d->status));
00244 log(WvLog::Info, msg);
00245 err.seterr(msg);
00246 d->user = WvString::null;
00247 d->groups.zap();
00248 return false;
00249 }
00250 }
00251
00252
00253 WvString WvPam::getuser() const
00254 {
00255 return d->user;
00256 }
00257
00258
00259 void WvPam::getgroups(WvStringList &l) const
00260 {
00261 assert(l.isempty());
00262
00263
00264 if (d->groups.isempty())
00265 {
00266 setgrent();
00267 struct group *gr;
00268 while ((gr = getgrent()))
00269 {
00270 for (char **i = gr->gr_mem; *i != NULL; i++)
00271 {
00272 if (strcmp(*i, d->user) == 0)
00273 {
00274 d->groups.append(new WvString(gr->gr_name), true);
00275 break;
00276 }
00277 }
00278 }
00279 endgrent();
00280 }
00281
00282 WvStringList::Iter i(d->groups);
00283 for (i.rewind(); i.next(); )
00284 l.append(new WvString(*i), true);
00285 }
00286
00287
00288
00289
00290
00291
00292 #endif // HAVE_SECURITY_PAM_APPL_H