Fix several warnings that appear in gcc 4.3.2.
[wvstreams.git] / utils / wvpam.cc
blob0b9d7a545c0827888e8dc2e50d13676dabc74bac
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2003 Net Integration Technologies, Inc.
5 * A WvStream that authenticates with PAM before allowing any reading or
6 * writing. See wvpam.h.
7 */
8 #include "wvlog.h"
9 #include "wvpam.h"
10 #include "wvautoconf.h"
12 // If PAM not installed at compile time, stub this out
13 #ifndef HAVE_SECURITY_PAM_APPL_H
15 WvPam::WvPam(WvStringParm _appname)
16 : log("PAM Auth", WvLog::Info), appname(_appname)
18 err.seterr("Compiled without PAM Support!\n");
22 WvPam::WvPam(WvStringParm _appname, WvStringParm rhost,
23 WvStringParm user, WvStringParm password)
24 : log("PAM Auth", WvLog::Info), appname(_appname)
26 err.seterr("Compiled without PAM Support!\n");
30 WvPam::~WvPam()
34 bool WvPam::authenticate(WvStringParm rhost, WvStringParm user, WvStringParm password)
36 return false;
39 WvString WvPam::getuser() const
41 return WvString::null;
45 void WvPam::getgroups(WvStringList &l) const
49 #else // HAVE_SECURITY_PAM_APPL_H
51 #include <security/pam_appl.h>
52 #include <sys/types.h>
53 #include <pwd.h>
54 #include <grp.h>
56 #include "wvaddr.h"
59 class WvPamData
61 public:
62 pam_handle_t *pamh;
63 int status;
64 WvString failmsg, user;
65 WvStringList groups;
67 WvPamData()
68 : pamh(NULL), status(PAM_SUCCESS), user("")
69 { }
71 WvPamData(WvStringParm _failmsg)
72 : pamh(NULL), status(PAM_SUCCESS), failmsg(_failmsg)
73 { }
77 /** noconv: null PAM conversation function */
78 #if HAVE_BROKEN_PAM
79 int noconv(int num_msg, struct pam_message **msgm,
80 struct pam_response **response, void *userdata)
81 #else
82 int noconv(int num_msg, const struct pam_message **msgm,
83 struct pam_response **response, void *userdata)
84 #endif
86 // if you need to ask things, it won't work
87 return PAM_CONV_ERR;
91 // The password gets passed in from userdata, and we simply echo it back
92 // out in the response... *sigh* This is because pam expects this function
93 // to actually interact with the user, and get their password.
94 #if HAVE_BROKEN_PAM
95 static int passconv(int num_msg, struct pam_message **msgm,
96 struct pam_response **response, void *userdata)
97 #else
98 static int passconv(int num_msg, const struct pam_message **msgm,
99 struct pam_response **response, void *userdata)
100 #endif
102 struct pam_response *password_echo;
104 password_echo = (struct pam_response *)calloc(num_msg,
105 sizeof(struct pam_response));
106 password_echo->resp = (char *)userdata;
107 password_echo->resp_retcode = 0;
109 *response = password_echo;
111 return PAM_SUCCESS;
114 WvPam::WvPam(WvStringParm _appname)
115 : log("PAM Auth", WvLog::Info), appname(_appname)
117 init();
121 WvPam::WvPam(WvStringParm _appname, WvStringParm rhost,
122 WvStringParm user, WvStringParm password)
123 : log("PAM Auth", WvLog::Info), appname(_appname)
125 if (init())
126 authenticate(rhost, user, password);
129 WvPam::~WvPam()
131 log(WvLog::Debug2, "Shutting down PAM Session for: %s\n", appname);
132 if (d->status == PAM_SUCCESS)
133 pam_close_session(d->pamh, 0);
134 pam_end(d->pamh, d->status);
135 d->groups.zap();
136 delete d;
140 bool WvPam::init()
142 d = new WvPamData();
143 log(WvLog::Debug2, "Starting up PAM Session for: %s\n", appname);
144 err.seterr("Not yet authenticated...");
146 struct pam_conv c;
147 c.conv = noconv;
148 c.appdata_ptr = NULL;
150 d->pamh = NULL;
151 d->status = pam_start(appname, d->user, &c, &d->pamh);
152 if (check_pam_status("pam_start")) return true;
153 return false;
156 bool WvPam::authenticate(WvStringParm rhost, WvStringParm user, WvStringParm password)
158 // Just in case...
159 assert(d);
161 if (!!rhost)
163 d->status = pam_set_item(d->pamh, PAM_RHOST, rhost);
164 if (!check_pam_status("rhost setup"))
165 return false;
168 if (!!user)
170 d->user = user;
171 d->status = pam_set_item(d->pamh, PAM_USER, user);
172 if (!check_pam_status("user setup"))
173 return false;
176 if (!!password)
178 struct pam_conv c;
179 c.conv = passconv;
180 c.appdata_ptr = strdup(password);
181 d->status = pam_set_item(d->pamh, PAM_CONV, &c);
182 if (!check_pam_status("conversation setup"))
183 return false;
185 d->status = pam_set_item(d->pamh, PAM_AUTHTOK, password);
186 if (!check_pam_status("password setup"))
187 return false;
190 #if HAVE_BROKEN_PAM
191 void *x = NULL;
192 #else
193 const void *x = NULL;
194 #endif
195 d->status = pam_get_item(d->pamh, PAM_USER, &x);
196 if (!check_pam_status("get username"))
197 return false;
198 d->user = (const char *)x;
199 d->user.unique();
201 log("Starting Authentication for %s@%s\n", d->user, rhost);
203 d->status = pam_authenticate(d->pamh, PAM_DISALLOW_NULL_AUTHTOK | PAM_SILENT);
204 if (!check_pam_status("authentication")) return false;
206 d->status = pam_acct_mgmt(d->pamh, PAM_DISALLOW_NULL_AUTHTOK | PAM_SILENT);
207 if (!check_pam_status("account management")) return false;
209 d->status = pam_setcred(d->pamh, PAM_ESTABLISH_CRED);
210 if (!check_pam_status("credentials")) return false;
212 d->status = pam_open_session(d->pamh, 0);
213 if (!check_pam_status("session open")) return false;
215 // Grab the current user name (now that we've authenticated)
216 if (!d->user)
218 #ifdef SOLARIS
219 void *x = NULL;
220 #else
221 const void *x = NULL;
222 #endif
223 d->status = pam_get_item(d->pamh, PAM_USER, &x);
224 if (!check_pam_status("get username")) return false;
225 d->user = (const char *)x;
226 d->user.unique();
228 log("Session open as user '%s'\n", d->user);
230 // If we made it here, we're clear of everything, and we can go
231 // to a no error status.
232 err.noerr();
234 return true;
238 bool WvPam::check_pam_status(WvStringParm s)
240 if (d->status == PAM_SUCCESS)
242 log(WvLog::Debug2, "PAM %s succeeded.\n", s);
243 return true;
245 else
247 WvString msg("PAM %s failed: %s\n", s, pam_strerror(d->pamh, d->status));
248 log(WvLog::Info, msg);
249 err.seterr(msg);
250 d->user = WvString::null;
251 d->groups.zap();
252 return false;
257 WvString WvPam::getuser() const
259 return d->user;
263 void WvPam::getgroups(WvStringList &l) const
265 assert(l.isempty());
267 // Cache after the first time...
268 if (d->groups.isempty())
270 setgrent();
271 struct group *gr;
272 while ((gr = getgrent()))
274 for (char **i = gr->gr_mem; *i != NULL; i++)
276 if (strcmp(*i, d->user) == 0)
278 d->groups.append(new WvString(gr->gr_name), true);
279 break;
283 endgrent();
286 WvStringList::Iter i(d->groups);
287 for (i.rewind(); i.next(); )
288 l.append(new WvString(*i), true);
296 #endif // HAVE_SECURITY_PAM_APPL_H