1242be47eSzrj /*-
2*c98db407SSascha Wildner * SPDX-License-Identifier: BSD-3-Clause
3*c98db407SSascha Wildner *
4242be47eSzrj * Copyright 1998 Juniper Networks, Inc.
5242be47eSzrj * All rights reserved.
6242be47eSzrj * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
7242be47eSzrj * All rights reserved.
8242be47eSzrj *
9242be47eSzrj * Portions of this software was developed for the FreeBSD Project by
10242be47eSzrj * ThinkSec AS and NAI Labs, the Security Research Division of Network
11242be47eSzrj * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
12242be47eSzrj * ("CBOSS"), as part of the DARPA CHATS research program.
13242be47eSzrj *
14242be47eSzrj * Redistribution and use in source and binary forms, with or without
15242be47eSzrj * modification, are permitted provided that the following conditions
16242be47eSzrj * are met:
17242be47eSzrj * 1. Redistributions of source code must retain the above copyright
18242be47eSzrj * notice, this list of conditions and the following disclaimer.
19242be47eSzrj * 2. Redistributions in binary form must reproduce the above copyright
20242be47eSzrj * notice, this list of conditions and the following disclaimer in the
21242be47eSzrj * documentation and/or other materials provided with the distribution.
22242be47eSzrj * 3. The name of the author may not be used to endorse or promote
23242be47eSzrj * products derived from this software without specific prior written
24242be47eSzrj * permission.
25242be47eSzrj *
26242be47eSzrj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27242be47eSzrj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28242be47eSzrj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29242be47eSzrj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30242be47eSzrj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31242be47eSzrj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32242be47eSzrj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33242be47eSzrj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34242be47eSzrj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35242be47eSzrj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36242be47eSzrj * SUCH DAMAGE.
37242be47eSzrj *
38*c98db407SSascha Wildner * $FreeBSD: head/lib/libpam/modules/pam_unix/pam_unix.c 326219 2017-11-26 02:00:33Z pfg $
39242be47eSzrj */
40242be47eSzrj
41242be47eSzrj #include <sys/param.h>
42242be47eSzrj #include <sys/socket.h>
43242be47eSzrj #include <sys/time.h>
44242be47eSzrj #include <netinet/in.h>
45242be47eSzrj #include <arpa/inet.h>
46242be47eSzrj
47242be47eSzrj #include <login_cap.h>
48242be47eSzrj #include <netdb.h>
49242be47eSzrj #include <pwd.h>
50242be47eSzrj #include <stdlib.h>
51242be47eSzrj #include <string.h>
52242be47eSzrj #include <stdio.h>
53242be47eSzrj #include <syslog.h>
54242be47eSzrj #include <time.h>
55242be47eSzrj #include <unistd.h>
56242be47eSzrj
57242be47eSzrj #include <libutil.h>
58242be47eSzrj
59242be47eSzrj #ifdef YP
60242be47eSzrj #include <ypclnt.h>
61242be47eSzrj #endif
62242be47eSzrj
63242be47eSzrj #define PAM_SM_AUTH
64242be47eSzrj #define PAM_SM_ACCOUNT
65242be47eSzrj #define PAM_SM_PASSWORD
66242be47eSzrj
67242be47eSzrj #include <security/pam_appl.h>
68242be47eSzrj #include <security/pam_modules.h>
69242be47eSzrj #include <security/pam_mod_misc.h>
70242be47eSzrj
71242be47eSzrj #define PASSWORD_HASH "sha512"
72242be47eSzrj #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
73242be47eSzrj #define SALTSIZE 32
74242be47eSzrj
75242be47eSzrj #define LOCKED_PREFIX "*LOCKED*"
76242be47eSzrj #define LOCKED_PREFIX_LEN (sizeof(LOCKED_PREFIX) - 1)
77242be47eSzrj
78242be47eSzrj static void makesalt(char []);
79242be47eSzrj
80242be47eSzrj static char password_hash[] = PASSWORD_HASH;
81242be47eSzrj
82242be47eSzrj #define PAM_OPT_LOCAL_PASS "local_pass"
83242be47eSzrj #define PAM_OPT_NIS_PASS "nis_pass"
84242be47eSzrj
85242be47eSzrj /*
86242be47eSzrj * authentication management
87242be47eSzrj */
88242be47eSzrj PAM_EXTERN int
pam_sm_authenticate(pam_handle_t * pamh,int flags __unused,int argc __unused,const char * argv[]__unused)89242be47eSzrj pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
90242be47eSzrj int argc __unused, const char *argv[] __unused)
91242be47eSzrj {
92242be47eSzrj login_cap_t *lc;
93242be47eSzrj struct passwd *pwd;
94242be47eSzrj int retval;
95242be47eSzrj const char *pass, *user, *realpw, *prompt;
96242be47eSzrj char *cryptpw;
97242be47eSzrj
98242be47eSzrj if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF)) {
99*c98db407SSascha Wildner user = getlogin();
100242be47eSzrj } else {
101242be47eSzrj retval = pam_get_user(pamh, &user, NULL);
102242be47eSzrj if (retval != PAM_SUCCESS)
103242be47eSzrj return (retval);
104242be47eSzrj }
105*c98db407SSascha Wildner pwd = getpwnam(user);
106242be47eSzrj
107242be47eSzrj PAM_LOG("Got user: %s", user);
108242be47eSzrj
109242be47eSzrj if (pwd != NULL) {
110242be47eSzrj PAM_LOG("Doing real authentication");
111242be47eSzrj realpw = pwd->pw_passwd;
112242be47eSzrj if (realpw[0] == '\0') {
113242be47eSzrj if (!(flags & PAM_DISALLOW_NULL_AUTHTOK) &&
114242be47eSzrj openpam_get_option(pamh, PAM_OPT_NULLOK))
115242be47eSzrj return (PAM_SUCCESS);
116*c98db407SSascha Wildner PAM_LOG("Password is empty, using fake password");
117242be47eSzrj realpw = "*";
118242be47eSzrj }
119242be47eSzrj lc = login_getpwclass(pwd);
120242be47eSzrj } else {
121242be47eSzrj PAM_LOG("Doing dummy authentication");
122242be47eSzrj realpw = "*";
123242be47eSzrj lc = login_getclass(NULL);
124242be47eSzrj }
125242be47eSzrj prompt = login_getcapstr(lc, "passwd_prompt", NULL, NULL);
126242be47eSzrj retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, prompt);
127242be47eSzrj login_close(lc);
128242be47eSzrj if (retval != PAM_SUCCESS)
129242be47eSzrj return (retval);
130242be47eSzrj PAM_LOG("Got password");
131*c98db407SSascha Wildner if (strnlen(pass, _PASSWORD_LEN + 1) > _PASSWORD_LEN) {
132*c98db407SSascha Wildner PAM_LOG("Password is too long, using fake password");
133*c98db407SSascha Wildner realpw = "*";
134*c98db407SSascha Wildner }
135242be47eSzrj cryptpw = crypt(pass, realpw);
136242be47eSzrj if (cryptpw != NULL && strcmp(cryptpw, realpw) == 0)
137242be47eSzrj return (PAM_SUCCESS);
138242be47eSzrj
139242be47eSzrj PAM_VERBOSE_ERROR("UNIX authentication refused");
140242be47eSzrj return (PAM_AUTH_ERR);
141242be47eSzrj }
142242be47eSzrj
143242be47eSzrj PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh __unused,int flags __unused,int argc __unused,const char * argv[]__unused)144242be47eSzrj pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
145242be47eSzrj int argc __unused, const char *argv[] __unused)
146242be47eSzrj {
147242be47eSzrj
148242be47eSzrj return (PAM_SUCCESS);
149242be47eSzrj }
150242be47eSzrj
151242be47eSzrj /*
152242be47eSzrj * account management
153242be47eSzrj */
154242be47eSzrj PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t * pamh,int flags __unused,int argc __unused,const char * argv[]__unused)155242be47eSzrj pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
156242be47eSzrj int argc __unused, const char *argv[] __unused)
157242be47eSzrj {
158242be47eSzrj struct addrinfo hints, *res;
159242be47eSzrj struct passwd *pwd;
160242be47eSzrj struct timeval tp;
161242be47eSzrj login_cap_t *lc;
162242be47eSzrj time_t warntime;
163242be47eSzrj int retval;
164242be47eSzrj const char *user;
165242be47eSzrj const void *rhost, *tty;
166242be47eSzrj char rhostip[MAXHOSTNAMELEN] = "";
167242be47eSzrj
168242be47eSzrj retval = pam_get_user(pamh, &user, NULL);
169242be47eSzrj if (retval != PAM_SUCCESS)
170242be47eSzrj return (retval);
171242be47eSzrj
172242be47eSzrj if (user == NULL || (pwd = getpwnam(user)) == NULL)
173242be47eSzrj return (PAM_SERVICE_ERR);
174242be47eSzrj
175242be47eSzrj PAM_LOG("Got user: %s", user);
176242be47eSzrj
177242be47eSzrj retval = pam_get_item(pamh, PAM_RHOST, &rhost);
178242be47eSzrj if (retval != PAM_SUCCESS)
179242be47eSzrj return (retval);
180242be47eSzrj
181242be47eSzrj retval = pam_get_item(pamh, PAM_TTY, &tty);
182242be47eSzrj if (retval != PAM_SUCCESS)
183242be47eSzrj return (retval);
184242be47eSzrj
185242be47eSzrj if (*pwd->pw_passwd == '\0' &&
186242be47eSzrj (flags & PAM_DISALLOW_NULL_AUTHTOK) != 0)
187242be47eSzrj return (PAM_NEW_AUTHTOK_REQD);
188242be47eSzrj
189242be47eSzrj if (strncmp(pwd->pw_passwd, LOCKED_PREFIX, LOCKED_PREFIX_LEN) == 0)
190242be47eSzrj return (PAM_AUTH_ERR);
191242be47eSzrj
192242be47eSzrj lc = login_getpwclass(pwd);
193242be47eSzrj if (lc == NULL) {
194242be47eSzrj PAM_LOG("Unable to get login class for user %s", user);
195242be47eSzrj return (PAM_SERVICE_ERR);
196242be47eSzrj }
197242be47eSzrj
198242be47eSzrj PAM_LOG("Got login_cap");
199242be47eSzrj
200242be47eSzrj if (pwd->pw_change || pwd->pw_expire)
201242be47eSzrj gettimeofday(&tp, NULL);
202242be47eSzrj
203242be47eSzrj /*
204242be47eSzrj * Check pw_expire before pw_change - no point in letting the
205242be47eSzrj * user change the password on an expired account.
206242be47eSzrj */
207242be47eSzrj
208242be47eSzrj if (pwd->pw_expire) {
209242be47eSzrj warntime = login_getcaptime(lc, "warnexpire",
210242be47eSzrj DEFAULT_WARN, DEFAULT_WARN);
211242be47eSzrj if (tp.tv_sec >= pwd->pw_expire) {
212242be47eSzrj login_close(lc);
213242be47eSzrj return (PAM_ACCT_EXPIRED);
214242be47eSzrj } else if (pwd->pw_expire - tp.tv_sec < warntime &&
215242be47eSzrj (flags & PAM_SILENT) == 0) {
216242be47eSzrj pam_error(pamh, "Warning: your account expires on %s",
217242be47eSzrj ctime(&pwd->pw_expire));
218242be47eSzrj }
219242be47eSzrj }
220242be47eSzrj
221242be47eSzrj retval = PAM_SUCCESS;
222242be47eSzrj if (pwd->pw_change) {
223242be47eSzrj warntime = login_getcaptime(lc, "warnpassword",
224242be47eSzrj DEFAULT_WARN, DEFAULT_WARN);
225242be47eSzrj if (tp.tv_sec >= pwd->pw_change) {
226242be47eSzrj retval = PAM_NEW_AUTHTOK_REQD;
227242be47eSzrj } else if (pwd->pw_change - tp.tv_sec < warntime &&
228242be47eSzrj (flags & PAM_SILENT) == 0) {
229242be47eSzrj pam_error(pamh, "Warning: your password expires on %s",
230242be47eSzrj ctime(&pwd->pw_change));
231242be47eSzrj }
232242be47eSzrj }
233242be47eSzrj
234242be47eSzrj /*
235242be47eSzrj * From here on, we must leave retval untouched (unless we
236242be47eSzrj * know we're going to fail), because we need to remember
237242be47eSzrj * whether we're supposed to return PAM_SUCCESS or
238242be47eSzrj * PAM_NEW_AUTHTOK_REQD.
239242be47eSzrj */
240242be47eSzrj
241242be47eSzrj if (rhost && *(const char *)rhost != '\0') {
242242be47eSzrj memset(&hints, 0, sizeof(hints));
243242be47eSzrj hints.ai_family = AF_UNSPEC;
244242be47eSzrj if (getaddrinfo(rhost, NULL, &hints, &res) == 0) {
245242be47eSzrj getnameinfo(res->ai_addr, res->ai_addrlen,
246242be47eSzrj rhostip, sizeof(rhostip), NULL, 0,
247242be47eSzrj NI_NUMERICHOST);
248242be47eSzrj }
249242be47eSzrj if (res != NULL)
250242be47eSzrj freeaddrinfo(res);
251242be47eSzrj }
252242be47eSzrj
253242be47eSzrj /*
254242be47eSzrj * Check host / tty / time-of-day restrictions
255242be47eSzrj */
256242be47eSzrj
257242be47eSzrj if (!auth_hostok(lc, rhost, rhostip) ||
258242be47eSzrj !auth_ttyok(lc, tty) ||
259242be47eSzrj !auth_timeok(lc, time(NULL)))
260242be47eSzrj retval = PAM_AUTH_ERR;
261242be47eSzrj
262242be47eSzrj login_close(lc);
263242be47eSzrj
264242be47eSzrj return (retval);
265242be47eSzrj }
266242be47eSzrj
267242be47eSzrj /*
268242be47eSzrj * password management
269242be47eSzrj *
270242be47eSzrj * standard Unix and NIS password changing
271242be47eSzrj */
272242be47eSzrj PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc __unused,const char * argv[]__unused)273242be47eSzrj pam_sm_chauthtok(pam_handle_t *pamh, int flags,
274242be47eSzrj int argc __unused, const char *argv[] __unused)
275242be47eSzrj {
276242be47eSzrj #ifdef YP
277242be47eSzrj struct ypclnt *ypclnt;
278242be47eSzrj const void *yp_domain, *yp_server;
279242be47eSzrj #endif
280242be47eSzrj char salt[SALTSIZE + 1];
281242be47eSzrj login_cap_t *lc;
282242be47eSzrj struct passwd *pwd, *old_pwd;
283242be47eSzrj const char *user, *old_pass, *new_pass;
284242be47eSzrj char *encrypted;
285242be47eSzrj time_t passwordtime;
286242be47eSzrj int pfd, tfd, retval;
287242be47eSzrj
288242be47eSzrj if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF))
289*c98db407SSascha Wildner user = getlogin();
290242be47eSzrj else {
291242be47eSzrj retval = pam_get_user(pamh, &user, NULL);
292242be47eSzrj if (retval != PAM_SUCCESS)
293242be47eSzrj return (retval);
294242be47eSzrj }
295*c98db407SSascha Wildner pwd = getpwnam(user);
296242be47eSzrj
297242be47eSzrj if (pwd == NULL)
298242be47eSzrj return (PAM_AUTHTOK_RECOVERY_ERR);
299242be47eSzrj
300242be47eSzrj PAM_LOG("Got user: %s", user);
301242be47eSzrj
302242be47eSzrj if (flags & PAM_PRELIM_CHECK) {
303242be47eSzrj
304242be47eSzrj PAM_LOG("PRELIM round");
305242be47eSzrj
306242be47eSzrj if (getuid() == 0 &&
307242be47eSzrj (pwd->pw_fields & _PWF_SOURCE) == _PWF_FILES)
308242be47eSzrj /* root doesn't need the old password */
309242be47eSzrj return (pam_set_item(pamh, PAM_OLDAUTHTOK, ""));
310242be47eSzrj #ifdef YP
311242be47eSzrj if (getuid() == 0 &&
312242be47eSzrj (pwd->pw_fields & _PWF_SOURCE) == _PWF_NIS) {
313242be47eSzrj
314242be47eSzrj yp_domain = yp_server = NULL;
315242be47eSzrj pam_get_data(pamh, "yp_domain", &yp_domain);
316242be47eSzrj pam_get_data(pamh, "yp_server", &yp_server);
317242be47eSzrj
318242be47eSzrj ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_server);
319242be47eSzrj if (ypclnt == NULL)
320242be47eSzrj return (PAM_BUF_ERR);
321242be47eSzrj
322242be47eSzrj if (ypclnt_connect(ypclnt) == -1) {
323242be47eSzrj ypclnt_free(ypclnt);
324242be47eSzrj return (PAM_SERVICE_ERR);
325242be47eSzrj }
326242be47eSzrj
327242be47eSzrj retval = ypclnt_havepasswdd(ypclnt);
328242be47eSzrj ypclnt_free(ypclnt);
329242be47eSzrj if (retval == 1)
330242be47eSzrj return (pam_set_item(pamh, PAM_OLDAUTHTOK, ""));
331242be47eSzrj else if (retval == -1)
332242be47eSzrj return (PAM_SERVICE_ERR);
333242be47eSzrj }
334242be47eSzrj #endif
335242be47eSzrj if (pwd->pw_passwd[0] == '\0'
336242be47eSzrj && openpam_get_option(pamh, PAM_OPT_NULLOK)) {
337242be47eSzrj /*
338242be47eSzrj * No password case. XXX Are we giving too much away
339242be47eSzrj * by not prompting for a password?
340242be47eSzrj * XXX check PAM_DISALLOW_NULL_AUTHTOK
341242be47eSzrj */
342242be47eSzrj old_pass = "";
343*c98db407SSascha Wildner retval = PAM_SUCCESS;
344242be47eSzrj } else {
345242be47eSzrj retval = pam_get_authtok(pamh,
346242be47eSzrj PAM_OLDAUTHTOK, &old_pass, NULL);
347242be47eSzrj if (retval != PAM_SUCCESS)
348242be47eSzrj return (retval);
349242be47eSzrj }
350242be47eSzrj PAM_LOG("Got old password");
351242be47eSzrj /* always encrypt first */
352242be47eSzrj encrypted = crypt(old_pass, pwd->pw_passwd);
353242be47eSzrj if (old_pass[0] == '\0' &&
354242be47eSzrj !openpam_get_option(pamh, PAM_OPT_NULLOK))
355242be47eSzrj return (PAM_PERM_DENIED);
356242be47eSzrj if (encrypted == NULL || strcmp(encrypted, pwd->pw_passwd) != 0)
357242be47eSzrj return (PAM_PERM_DENIED);
358242be47eSzrj }
359242be47eSzrj else if (flags & PAM_UPDATE_AUTHTOK) {
360242be47eSzrj PAM_LOG("UPDATE round");
361242be47eSzrj
362242be47eSzrj retval = pam_get_authtok(pamh,
363242be47eSzrj PAM_OLDAUTHTOK, &old_pass, NULL);
364242be47eSzrj if (retval != PAM_SUCCESS)
365242be47eSzrj return (retval);
366242be47eSzrj PAM_LOG("Got old password");
367242be47eSzrj
368242be47eSzrj /* get new password */
369242be47eSzrj for (;;) {
370242be47eSzrj retval = pam_get_authtok(pamh,
371242be47eSzrj PAM_AUTHTOK, &new_pass, NULL);
372242be47eSzrj if (retval != PAM_TRY_AGAIN)
373242be47eSzrj break;
374242be47eSzrj pam_error(pamh, "Mismatch; try again, EOF to quit.");
375242be47eSzrj }
376242be47eSzrj PAM_LOG("Got new password");
377242be47eSzrj if (retval != PAM_SUCCESS) {
378242be47eSzrj PAM_VERBOSE_ERROR("Unable to get new password");
379242be47eSzrj return (retval);
380242be47eSzrj }
381242be47eSzrj
382242be47eSzrj if (getuid() != 0 && new_pass[0] == '\0' &&
383242be47eSzrj !openpam_get_option(pamh, PAM_OPT_NULLOK))
384242be47eSzrj return (PAM_PERM_DENIED);
385242be47eSzrj
386242be47eSzrj if ((old_pwd = pw_dup(pwd)) == NULL)
387242be47eSzrj return (PAM_BUF_ERR);
388242be47eSzrj
389242be47eSzrj lc = login_getclass(pwd->pw_class);
390242be47eSzrj if (login_setcryptfmt(lc, password_hash, NULL) == NULL)
391242be47eSzrj openpam_log(PAM_LOG_ERROR,
392242be47eSzrj "can't set password cipher, relying on default");
393242be47eSzrj
394242be47eSzrj /* set password expiry date */
395242be47eSzrj pwd->pw_change = 0;
396242be47eSzrj passwordtime = login_getcaptime(lc, "passwordtime", 0, 0);
397242be47eSzrj if (passwordtime > 0)
398242be47eSzrj pwd->pw_change = time(NULL) + passwordtime;
399242be47eSzrj
400242be47eSzrj login_close(lc);
401242be47eSzrj makesalt(salt);
402242be47eSzrj pwd->pw_passwd = crypt(new_pass, salt);
403242be47eSzrj #ifdef YP
404242be47eSzrj switch (old_pwd->pw_fields & _PWF_SOURCE) {
405242be47eSzrj case _PWF_FILES:
406242be47eSzrj #endif
407242be47eSzrj retval = PAM_SERVICE_ERR;
408242be47eSzrj if (pw_init(NULL, NULL))
409242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_init() failed");
410242be47eSzrj else if ((pfd = pw_lock()) == -1)
411242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_lock() failed");
412242be47eSzrj else if ((tfd = pw_tmp(-1)) == -1)
413242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_tmp() failed");
414242be47eSzrj else if (pw_copy(pfd, tfd, pwd, old_pwd) == -1)
415242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_copy() failed");
416242be47eSzrj else if (pw_mkdb(pwd->pw_name) == -1)
417242be47eSzrj openpam_log(PAM_LOG_ERROR, "pw_mkdb() failed");
418242be47eSzrj else
419242be47eSzrj retval = PAM_SUCCESS;
420242be47eSzrj pw_fini();
421242be47eSzrj #ifdef YP
422242be47eSzrj break;
423242be47eSzrj case _PWF_NIS:
424242be47eSzrj yp_domain = yp_server = NULL;
425242be47eSzrj pam_get_data(pamh, "yp_domain", &yp_domain);
426242be47eSzrj pam_get_data(pamh, "yp_server", &yp_server);
427242be47eSzrj ypclnt = ypclnt_new(yp_domain,
428242be47eSzrj "passwd.byname", yp_server);
429242be47eSzrj if (ypclnt == NULL) {
430242be47eSzrj retval = PAM_BUF_ERR;
431242be47eSzrj } else if (ypclnt_connect(ypclnt) == -1 ||
432242be47eSzrj ypclnt_passwd(ypclnt, pwd, old_pass) == -1) {
433242be47eSzrj openpam_log(PAM_LOG_ERROR, "%s", ypclnt->error);
434242be47eSzrj retval = PAM_SERVICE_ERR;
435242be47eSzrj } else {
436242be47eSzrj retval = PAM_SUCCESS;
437242be47eSzrj }
438242be47eSzrj ypclnt_free(ypclnt);
439242be47eSzrj break;
440242be47eSzrj default:
441242be47eSzrj openpam_log(PAM_LOG_ERROR, "unsupported source 0x%x",
442242be47eSzrj pwd->pw_fields & _PWF_SOURCE);
443242be47eSzrj retval = PAM_SERVICE_ERR;
444242be47eSzrj }
445242be47eSzrj #endif
446242be47eSzrj free(old_pwd);
447242be47eSzrj }
448242be47eSzrj else {
449242be47eSzrj /* Very bad juju */
450242be47eSzrj retval = PAM_ABORT;
451242be47eSzrj PAM_LOG("Illegal 'flags'");
452242be47eSzrj }
453242be47eSzrj
454242be47eSzrj return (retval);
455242be47eSzrj }
456242be47eSzrj
457242be47eSzrj /* Mostly stolen from passwd(1)'s local_passwd.c - markm */
458242be47eSzrj
459242be47eSzrj static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
460242be47eSzrj "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
461242be47eSzrj
462242be47eSzrj static void
to64(char * s,long v,int n)463242be47eSzrj to64(char *s, long v, int n)
464242be47eSzrj {
465242be47eSzrj while (--n >= 0) {
466242be47eSzrj *s++ = itoa64[v&0x3f];
467242be47eSzrj v >>= 6;
468242be47eSzrj }
469242be47eSzrj }
470242be47eSzrj
471242be47eSzrj /* Salt suitable for traditional DES and MD5 */
472242be47eSzrj static void
makesalt(char salt[SALTSIZE+1])473242be47eSzrj makesalt(char salt[SALTSIZE + 1])
474242be47eSzrj {
475242be47eSzrj int i;
476242be47eSzrj
477242be47eSzrj /* These are not really random numbers, they are just
478242be47eSzrj * numbers that change to thwart construction of a
479242be47eSzrj * dictionary.
480242be47eSzrj */
481242be47eSzrj for (i = 0; i < SALTSIZE; i += 4)
482242be47eSzrj to64(&salt[i], arc4random(), 4);
483242be47eSzrj salt[SALTSIZE] = '\0';
484242be47eSzrj }
485242be47eSzrj
486242be47eSzrj PAM_MODULE_ENTRY("pam_unix");
487