Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvpam.cc

Go to the documentation of this file.
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.  If WvStreams is compiled without PAM, it just fails.
00007  *
00008  * For now, this only works for PAM modules that don't require any user
00009  * interaction.
00010  */
00011 
00012 #include "wvlog.h"
00013 #include "wvpam.h"
00014 #include "wvautoconf.h"
00015 
00016 // If PAM not installed at compile time, stub this out
00017 #ifndef HAVE_SECURITY_PAM_APPL_H
00018 
00019 WvPamStream::WvPamStream(WvStream *cloned, WvStringParm name, WvStringParm
00020         success, WvStringParm fail) :
00021     WvStreamClone(cloned)
00022 {
00023     WvLog log("WvPamStream", WvLog::Warning);
00024     log("Compiled without PAM support\n");
00025     if (cloned && !!fail)
00026         cloned->write(fail.cstr(), fail.len());
00027 }
00028 
00029 WvPamStream::~WvPamStream()
00030 {
00031 }
00032 
00033 bool WvPamStream::isok() const
00034 {
00035     return false;
00036 }
00037 
00038 bool WvPamStream::check_pam_status(WvStringParm step)
00039 {
00040     return false;
00041 }
00042 
00043 WvString WvPamStream::getuser() const
00044 {
00045     return WvString::null;
00046 }
00047 
00048 void WvPamStream::getgroups(WvStringList &l) const
00049 {
00050 }
00051 
00052 #else   // HAVE_SECURITY_PAM_APPL_H
00053 
00054 #include <security/pam_appl.h>
00055 #include <sys/types.h>
00056 #include <pwd.h>
00057 #include <grp.h>
00058 
00059 #include "wvaddr.h"
00060 
00061 
00062 class WvPamData
00063 {
00064 public:
00065     pam_handle_t *pamh;
00066     int status;
00067     WvStringParm failmsg;
00068     WvString user;
00069     WvStringList groups;
00070 
00071     WvPamData(WvStringParm _failmsg) :
00072         pamh(NULL), status(PAM_SUCCESS), failmsg(_failmsg)
00073     { }
00074 };
00075 
00076 
00077 /** noconv: null PAM conversation function */
00078 int noconv(int num_msg, const struct pam_message **msgm,
00079         struct pam_response **response, void *userdata)
00080 {
00081     // if you need to ask things, it won't work
00082     return PAM_CONV_ERR;
00083 }
00084 
00085 
00086 // FIXME: pam calls could block.  Should fork off a subproc for this.  On the
00087 // other hand, the stream's blocked anyway until pam comes back, so do we
00088 // really care?
00089 WvPamStream::WvPamStream(WvStream *cloned, WvStringParm name,
00090         WvStringParm successmsg, WvStringParm failmsg) :
00091     WvStreamClone(cloned),
00092     d(new WvPamData(failmsg))
00093 {
00094     // create the conv structure
00095     struct pam_conv c;
00096     c.conv = noconv;
00097     c.appdata_ptr = NULL;
00098 
00099     // find the user
00100     struct passwd *pw = getpwuid(getuid());
00101     assert(pw);
00102     d->user = pw->pw_name;
00103 
00104     // find the host and port
00105     WvString rhost(*src());
00106  
00107     // authenticate through PAM
00108     d->status = pam_start(name, d->user, &c, &d->pamh);
00109     if (!check_pam_status("startup")) return;
00110 
00111     d->status = pam_set_item(d->pamh, PAM_RHOST, rhost);
00112     if (!check_pam_status("environment setup")) return;
00113 
00114     d->status = pam_authenticate(d->pamh, PAM_DISALLOW_NULL_AUTHTOK);
00115     if (!check_pam_status("authentication")) return;
00116 
00117     d->status = pam_setcred(d->pamh, PAM_ESTABLISH_CRED);
00118     if (!check_pam_status("credentials")) return;
00119 
00120     d->status = pam_open_session(d->pamh, 0);
00121     if (!check_pam_status("session open")) return;
00122 
00123     // write the success message if necessary
00124     if (cloned && !!successmsg) cloned->write(successmsg.cstr(), successmsg.len());
00125     
00126     // get the groups
00127     setgrent();
00128     struct group *gr;
00129     while ((gr = getgrent()))
00130     {
00131         for (char **i = gr->gr_mem; *i != NULL; i++)
00132         {
00133             if (strcmp(*i, d->user))
00134             {
00135                 d->groups.append(new WvString(gr->gr_name), true);
00136                 break;
00137             }
00138         }
00139     }
00140     endgrent();
00141 }
00142 
00143 
00144 WvPamStream::~WvPamStream()
00145 {
00146     if (d->status == PAM_SUCCESS)
00147         pam_close_session(d->pamh, 0);
00148     pam_end(d->pamh, d->status);
00149 }
00150 
00151 
00152 bool WvPamStream::isok() const
00153 {
00154     return (d->status == PAM_SUCCESS && WvStreamClone::isok());
00155 }
00156 
00157 
00158 bool WvPamStream::check_pam_status(WvStringParm s)
00159 {
00160     WvLog log("WvPamStream", WvLog::Debug2);
00161     if (d->status == PAM_SUCCESS)
00162     {
00163         log("PAM %s succeeded\n", s);
00164         return true;
00165     }
00166     else
00167     {
00168         log("PAM %s FAILED: %s\n", s, d->status);
00169         if (cloned && !!d->failmsg) cloned->write(d->failmsg.cstr(), d->failmsg.len());
00170         d->user = WvString::null;
00171         d->groups.zap();
00172         return false;
00173     }
00174 }
00175 
00176 
00177 WvString WvPamStream::getuser() const
00178 {
00179     return d->user;
00180 }
00181 
00182 
00183 void WvPamStream::getgroups(WvStringList &l) const
00184 {
00185     assert(l.isempty());
00186     WvStringList::Iter i(d->groups);
00187     for (i.rewind(); i.next(); )
00188         l.append(new WvString(*i), true);
00189 }
00190 
00191 
00192 #endif // HAVE_SECURITY_PAM_APPL_H

Generated on Sat Feb 21 21:05:31 2004 for WvStreams by doxygen 1.3.5