2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
15 #ifdef HAVE_SYS_WAIT_H
19 #include <security/pam_appl.h>
20 #include <security/pam_modules.h>
22 #include <afs/kautils.h>
23 #include "afs_message.h"
25 #include "afs_pam_msg.h"
27 #define RET(x) { retcode = (x); goto out; }
30 pam_sm_chauthtok(pam_handle_t
* pamh
, int flags
, int argc
, const char **argv
)
32 int retcode
= PAM_SUCCESS
;
33 int errcode
= PAM_SUCCESS
;
36 int logmask
= LOG_UPTO(LOG_INFO
);
38 int use_first_pass
= 0;
39 int try_first_pass
= 0;
41 char *torch_password
= NULL
;
43 char my_password_buf
[256];
48 PAM_CONST
char *user
= NULL
, *password
= NULL
;
49 char *new_password
= NULL
, *verify_password
= NULL
;
51 struct ktc_encryptionKey oldkey
, newkey
;
52 struct ktc_token token
;
53 struct ubik_client
*conn
= 0;
54 PAM_CONST
struct pam_conv
*pam_convp
= NULL
;
55 struct passwd
*upwd
= NULL
;
56 #if !(defined(AFS_LINUX20_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV) || defined(AFS_NBSD_ENV))
57 char upwd_buf
[2048]; /* size is a guess. */
58 struct passwd unix_pwd
;
62 openlog(pam_afs_ident
, LOG_CONS
, LOG_AUTH
);
64 origmask
= setlogmask(logmask
);
67 * Parse the user options. Log an error for any unknown options.
69 * Todo options: PAM_SILENT
71 for (i
= 0; i
< argc
; i
++) {
72 if (strcasecmp(argv
[i
], "debug") == 0) {
73 logmask
|= LOG_MASK(LOG_DEBUG
);
74 (void)setlogmask(logmask
);
75 } else if (strcasecmp(argv
[i
], "nowarn") == 0) {
77 } else if (strcasecmp(argv
[i
], "use_first_pass") == 0) {
79 } else if (strcasecmp(argv
[i
], "try_first_pass") == 0) {
81 } else if (strcasecmp(argv
[i
], "ignore_root") == 0) {
84 pam_afs_syslog(LOG_ERR
, PAMAFS_UNKNOWNOPT
, argv
[i
]);
91 if (logmask
& LOG_MASK(LOG_DEBUG
)) {
92 pam_afs_syslog(LOG_DEBUG
, PAMAFS_OPTIONS
, nowarn
, use_first_pass
,
94 pam_afs_syslog(LOG_DEBUG
, PAMAFS_PAMERROR
, flags
);
97 /* Try to get the user-interaction info, if available. */
98 errcode
= pam_get_item(pamh
, PAM_CONV
, (PAM_CONST
void **)&pam_convp
);
99 if (errcode
!= PAM_SUCCESS
) {
100 pam_afs_syslog(LOG_WARNING
, PAMAFS_NO_USER_INT
);
104 /* Who are we trying to authenticate here? */
106 pam_get_user(pamh
, &user
,
107 "AFS username: ")) != PAM_SUCCESS
) {
108 pam_afs_syslog(LOG_ERR
, PAMAFS_NOUSER
, errcode
);
109 RET(PAM_USER_UNKNOWN
);
112 if (logmask
& LOG_MASK(LOG_DEBUG
))
113 pam_afs_syslog(LOG_DEBUG
, PAMAFS_USERNAMEDEBUG
, user
);
116 * If the user has a "local" (or via nss, possibly nss_dce) pwent,
117 * and its uid==0, and "ignore_root" was given in pam.conf,
120 #if defined(AFS_HPUX_ENV) || defined(AFS_DARWIN100_ENV) || defined(AFS_SUN5_ENV)
121 #if defined(AFS_HPUX110_ENV) || defined(AFS_DARWIN100_ENV) || defined(AFS_SUN5_ENV)
122 i
= getpwnam_r(user
, &unix_pwd
, upwd_buf
, sizeof(upwd_buf
), &upwd
);
123 #else /* AFS_HPUX110_ENV */
124 i
= getpwnam_r(user
, &unix_pwd
, upwd_buf
, sizeof(upwd_buf
));
125 if (i
== 0) /* getpwnam_r success */
127 #endif /* else AFS_HPUX110_ENV */
128 if (ignore_root
&& i
== 0 && upwd
&& upwd
->pw_uid
== 0) {
129 pam_afs_syslog(LOG_INFO
, PAMAFS_IGNORINGROOT
, user
);
133 #if defined(AFS_LINUX20_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV) || defined(AFS_NBSD_ENV)
134 upwd
= getpwnam(user
);
136 upwd
= getpwnam_r(user
, &unix_pwd
, upwd_buf
, sizeof(upwd_buf
));
138 if (ignore_root
&& upwd
!= NULL
&& upwd
->pw_uid
== 0) {
139 pam_afs_syslog(LOG_INFO
, PAMAFS_IGNORINGROOT
, user
);
144 errcode
= pam_get_item(pamh
, PAM_AUTHTOK
, (PAM_CONST
void **)&password
);
145 if (errcode
!= PAM_SUCCESS
|| password
== NULL
) {
146 if (use_first_pass
) {
147 pam_afs_syslog(LOG_ERR
, PAMAFS_PASSWD_REQ
, user
);
150 password
= NULL
; /* In case it isn't already NULL */
151 if (logmask
& LOG_MASK(LOG_DEBUG
))
152 pam_afs_syslog(LOG_DEBUG
, PAMAFS_NOFIRSTPASS
, user
);
153 } else if (password
[0] == '\0') {
154 /* Actually we *did* get one but it was empty. */
155 pam_afs_syslog(LOG_INFO
, PAMAFS_NILPASSWORD
, user
);
156 RET(PAM_NEW_AUTHTOK_REQD
);
158 if (logmask
& LOG_MASK(LOG_DEBUG
))
159 pam_afs_syslog(LOG_DEBUG
, PAMAFS_GOTPASS
, user
);
161 if (!(use_first_pass
|| try_first_pass
)) {
165 if (password
== NULL
) {
166 char *prompt_password
;
168 RET(PAM_AUTH_ERR
); /* shouldn't happen */
171 if (pam_convp
== NULL
|| pam_convp
->conv
== NULL
) {
172 pam_afs_syslog(LOG_ERR
, PAMAFS_CANNOT_PROMPT
);
176 errcode
= pam_afs_prompt(pam_convp
, &prompt_password
, 0, PAMAFS_PWD_PROMPT
);
177 if (errcode
!= PAM_SUCCESS
|| prompt_password
== NULL
) {
178 pam_afs_syslog(LOG_ERR
, PAMAFS_GETPASS_FAILED
);
181 if (prompt_password
[0] == '\0') {
182 pam_afs_syslog(LOG_INFO
, PAMAFS_NILPASSWORD
, user
);
183 RET(PAM_NEW_AUTHTOK_REQD
);
187 * We aren't going to free the password later (we will wipe it,
188 * though), because the storage for it if we get it from other
189 * paths may belong to someone else. Since we do need to free
190 * this storage, copy it to a buffer that won't need to be freed
191 * later, and free this storage now.
193 strncpy(my_password_buf
, prompt_password
, sizeof(my_password_buf
));
194 my_password_buf
[sizeof(my_password_buf
) - 1] = '\0';
195 memset(prompt_password
, 0, strlen(prompt_password
));
196 free(prompt_password
);
197 password
= torch_password
= my_password_buf
;
200 if ((code
= ka_VerifyUserPassword(KA_USERAUTH_VERSION
+ KA_USERAUTH_DOSETPAG
, (char *)user
, /* kerberos name */
203 (char *)password
, /* password */
205 &reason
/* error string */ )) != 0) {
206 pam_afs_syslog(LOG_ERR
, PAMAFS_LOGIN_FAILED
, user
, reason
);
209 torch_password
= NULL
;
210 pam_set_item(pamh
, PAM_AUTHTOK
, password
);
211 pam_set_item(pamh
, PAM_OLDAUTHTOK
, password
);
212 if (flags
& PAM_PRELIM_CHECK
) {
213 /* only auth check was requested, so return success here */
214 return (PAM_SUCCESS
);
216 if (!(flags
& PAM_UPDATE_AUTHTOK
)) {
217 /* these lines are never executed ... */
218 /* UPDATE_AUTHTOK flag is required, return with error */
219 pam_afs_syslog(LOG_ERR
, PAMAFS_FLAGS
, "PAM_UPDATE_AUTHTOK");
223 /* get the new passwd and verify it */
225 pam_afs_prompt(pam_convp
, &new_password
, 0, PAMAFS_NEW_PWD_PROMPT
);
226 if (errcode
!= PAM_SUCCESS
|| new_password
== NULL
) {
227 pam_afs_syslog(LOG_ERR
, PAMAFS_GETPASS_FAILED
);
230 if (new_password
[0] == '\0') {
231 pam_afs_syslog(LOG_INFO
, PAMAFS_NILPASSWORD
, user
);
235 pam_afs_prompt(pam_convp
, &verify_password
, 0,
236 PAMAFS_VERIFY_PWD_PROMPT
);
237 if (errcode
!= PAM_SUCCESS
|| verify_password
== NULL
) {
238 pam_afs_syslog(LOG_ERR
, PAMAFS_GETPASS_FAILED
);
239 memset(new_password
, 0, strlen(new_password
));
242 if (verify_password
[0] == '\0') {
243 pam_afs_syslog(LOG_INFO
, PAMAFS_NILPASSWORD
, user
);
244 memset(new_password
, 0, strlen(new_password
));
247 if (strcmp(new_password
, verify_password
) != 0) {
248 pam_afs_syslog(LOG_INFO
, PAMAFS_NE_PASSWORD
);
249 memset(new_password
, 0, strlen(new_password
));
250 memset(verify_password
, 0, strlen(verify_password
));
253 memset(verify_password
, 0, strlen(verify_password
));
254 /* checking password length and quality is up to other PAM modules */
256 /* set the new password */
257 if ((code
= ka_Init(0)) != 0) {
258 pam_afs_syslog(LOG_ERR
, PAMAFS_KAERROR
, code
);
261 if ((code
= rx_Init(0)) != 0) {
262 pam_afs_syslog(LOG_ERR
, PAMAFS_KAERROR
, code
);
265 strcpy(instance
, "");
266 if ((localcell
= ka_LocalCell()) == NULL
) {
267 pam_afs_syslog(LOG_ERR
, PAMAFS_NOCELLNAME
);
270 strcpy(realm
, localcell
);
272 /* oldkey is not used in ka_ChangePassword (only for ka_auth) */
273 ka_StringToKey((char *)password
, realm
, &oldkey
);
274 ka_StringToKey(new_password
, realm
, &newkey
);
276 ka_GetAdminToken((char *)user
, instance
, realm
, &oldkey
, 20, &token
,
278 pam_afs_syslog(LOG_ERR
, PAMAFS_KAERROR
, code
);
282 ka_AuthServerConn(realm
, KA_MAINTENANCE_SERVICE
, &token
,
284 pam_afs_syslog(LOG_ERR
, PAMAFS_KAERROR
, code
);
287 if ((code
= ka_ChangePassword((char *)user
, /* kerberos name */
288 instance
, /* instance */
290 0, /* old password unused */
291 &newkey
/* new password */ )) != 0) {
292 pam_afs_syslog(LOG_ERR
, PAMAFS_KAPASS_FAIL
);
293 memset(new_password
, 0, strlen(new_password
));
296 pam_set_item(pamh
, PAM_AUTHTOK
, new_password
);
301 if (password
&& torch_password
) {
302 memset(torch_password
, 0, strlen(torch_password
));
304 (void)setlogmask(origmask
);