WvStreams
|
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2003 Net Integration Technologies, Inc. 00004 * 00005 * A WvStream that authenticates with PAM before allowing any reading or 00006 * writing. See wvpam.h. 00007 */ 00008 #include "wvlog.h" 00009 #include "wvpam.h" 00010 #include "wvautoconf.h" 00011 00012 // If PAM not installed at compile time, stub this out 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 // if you need to ask things, it won't work 00087 return PAM_CONV_ERR; 00088 } 00089 00090 00091 // The password gets passed in from userdata, and we simply echo it back 00092 // out in the response... *sigh* This is because pam expects this function 00093 // to actually interact with the user, and get their password. 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 // Just in case... 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 // Grab the current user name (now that we've authenticated) 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 // If we made it here, we're clear of everything, and we can go 00227 // to a no error status. 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 // Cache after the first time... 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