xref: /illumos-gate/usr/src/lib/pam_modules/unix_cred/unix_cred.c (revision 08e8465ea9de8f93d6ca817333b2ea217df7e3b2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <nss_dbdefs.h>
26 #include <pwd.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <syslog.h>
30 #include <unistd.h>
31 #include <auth_attr.h>
32 #include <deflt.h>
33 #include <priv.h>
34 #include <secdb.h>
35 #include <user_attr.h>
36 #include <sys/task.h>
37 #include <libintl.h>
38 #include <project.h>
39 #include <errno.h>
40 #include <alloca.h>
41 
42 #include <bsm/adt.h>
43 #include <bsm/adt_event.h>	/* adt_get_auid() */
44 
45 #include <security/pam_appl.h>
46 #include <security/pam_modules.h>
47 #include <security/pam_impl.h>
48 
49 #define	PROJECT		"project="
50 #define	PROJSZ		(sizeof (PROJECT) - 1)
51 
52 /*
53  *	unix_cred - PAM auth modules must contain both pam_sm_authenticate
54  *		and pam_sm_setcred.  Some other auth module is responsible
55  *		for authentication (e.g., pam_unix_auth.so), this module
56  *		only implements pam_sm_setcred so that the authentication
57  *		can be separated without knowledge of the Solaris Unix style
58  *		credential setting.
59  *		Solaris Unix style credential setting includes initializing
60  *		the audit characteristics if not already initialized and
61  *		setting the user's default and limit privileges.
62  */
63 
64 /*
65  *	unix_cred - pam_sm_authenticate
66  *
67  *	Returns	PAM_IGNORE.
68  */
69 
70 /*ARGSUSED*/
71 int
72 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
73 {
74 	return (PAM_IGNORE);
75 }
76 
77 /*
78  * Obtain a privilege set "keyname" from userattr; if none is present,
79  * fall back to the default, "defname".
80  */
81 static int
82 getset(char *keyname, char *defname, userattr_t *ua, priv_set_t **res,
83     void *defp)
84 {
85 	char *str;
86 	priv_set_t *tmp;
87 	char *badp;
88 	int len;
89 
90 	if ((ua == NULL || ua->attr == NULL ||
91 	    (str = kva_match(ua->attr, keyname)) == NULL) &&
92 	    (defp == NULL || (str = defread_r(defname, defp)) == NULL))
93 		return (0);
94 
95 	len = strlen(str) + 1;
96 	badp = alloca(len);
97 	(void) memset(badp, '\0', len);
98 	do {
99 		const char *q, *endp;
100 		tmp = priv_str_to_set(str, ",", &endp);
101 		if (tmp == NULL) {
102 			if (endp == NULL)
103 				break;
104 
105 			/* Now remove the bad privilege endp points to */
106 			q = strchr(endp, ',');
107 			if (q == NULL)
108 				q = endp + strlen(endp);
109 
110 			if (*badp != '\0')
111 				(void) strlcat(badp, ",", len);
112 			/* Memset above guarantees NUL termination */
113 			/* LINTED */
114 			(void) strncat(badp, endp, q - endp);
115 			/* excise bad privilege; strtok ignores 2x sep */
116 			(void) memmove((void *)endp, q, strlen(q) + 1);
117 		}
118 	} while (tmp == NULL && *str != '\0');
119 
120 	if (tmp == NULL) {
121 		syslog(LOG_AUTH|LOG_ERR,
122 		    "pam_setcred: can't parse privilege specification: %m\n");
123 		return (-1);
124 	} else if (*badp != '\0') {
125 		syslog(LOG_AUTH|LOG_DEBUG,
126 		    "pam_setcred: unrecognized privilege(s): %s\n", badp);
127 	}
128 	*res = tmp;
129 	return (0);
130 }
131 
132 /*
133  *	unix_cred - pam_sm_setcred
134  *
135  *	Entry flags = 	PAM_ESTABLISH_CRED, set up Solaris Unix cred.
136  *			PAM_DELETE_CRED, NOP, return PAM_SUCCESS.
137  *			PAM_REINITIALIZE_CRED, set up Solaris Unix cred,
138  *				or merge the current context with the new
139  *				user.
140  *			PAM_REFRESH_CRED, set up Solaris Unix cred.
141  *			PAM_SILENT, print no messages to user.
142  *
143  *	Returns	PAM_SUCCESS, if all successful.
144  *		PAM_CRED_ERR, if unable to set credentials.
145  *		PAM_USER_UNKNOWN, if PAM_USER not set, or unable to find
146  *			user in databases.
147  *		PAM_SYSTEM_ERR, if no valid flag, or unable to get/set
148  *			user's audit state.
149  */
150 
151 int
152 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
153 {
154 	int	i;
155 	int	debug = 0;
156 	uint_t	nowarn = flags & PAM_SILENT;
157 	int	ret = PAM_SUCCESS;
158 	char	*user;
159 	char	*auser;
160 	char	*rhost;
161 	char	*tty;
162 	au_id_t	auid;
163 	adt_session_data_t *ah;
164 	adt_termid_t	*termid = NULL;
165 	userattr_t	*ua;
166 	priv_set_t	*lim, *def, *tset;
167 	char		messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
168 	char		buf[PROJECT_BUFSZ];
169 	struct project	proj, *pproj;
170 	int		error;
171 	char		*projname;
172 	char		*kvs;
173 	struct passwd	pwd;
174 	char		pwbuf[NSS_BUFLEN_PASSWD];
175 	void		*defp;
176 
177 	for (i = 0; i < argc; i++) {
178 		if (strcmp(argv[i], "debug") == 0)
179 			debug = 1;
180 		else if (strcmp(argv[i], "nowarn") == 0)
181 			nowarn |= 1;
182 	}
183 
184 	if (debug)
185 		syslog(LOG_AUTH | LOG_DEBUG,
186 		    "pam_unix_cred: pam_sm_setcred(flags = %x, argc= %d)",
187 		    flags, argc);
188 
189 	(void) pam_get_item(pamh, PAM_USER, (void **)&user);
190 
191 	if (user == NULL || *user == '\0') {
192 		syslog(LOG_AUTH | LOG_ERR,
193 		    "pam_unix_cred: USER NULL or empty!\n");
194 		return (PAM_USER_UNKNOWN);
195 	}
196 	(void) pam_get_item(pamh, PAM_AUSER, (void **)&auser);
197 	(void) pam_get_item(pamh, PAM_RHOST, (void **)&rhost);
198 	(void) pam_get_item(pamh, PAM_TTY, (void **)&tty);
199 	if (debug)
200 		syslog(LOG_AUTH | LOG_DEBUG,
201 		    "pam_unix_cred: user = %s, auser = %s, rhost = %s, "
202 		    "tty = %s", user,
203 		    (auser == NULL) ? "NULL" : (*auser == '\0') ? "ZERO" :
204 		    auser,
205 		    (rhost == NULL) ? "NULL" : (*rhost == '\0') ? "ZERO" :
206 		    rhost,
207 		    (tty == NULL) ? "NULL" : (*tty == '\0') ? "ZERO" :
208 		    tty);
209 
210 	/* validate flags */
211 	switch (flags & (PAM_ESTABLISH_CRED | PAM_DELETE_CRED |
212 	    PAM_REINITIALIZE_CRED | PAM_REFRESH_CRED)) {
213 	case 0:
214 		/* set default flag */
215 		flags |= PAM_ESTABLISH_CRED;
216 		break;
217 	case PAM_ESTABLISH_CRED:
218 	case PAM_REINITIALIZE_CRED:
219 	case PAM_REFRESH_CRED:
220 		break;
221 	case PAM_DELETE_CRED:
222 		return (PAM_SUCCESS);
223 	default:
224 		syslog(LOG_AUTH | LOG_ERR,
225 		    "pam_unix_cred: invalid flags %x", flags);
226 		return (PAM_SYSTEM_ERR);
227 	}
228 
229 	/*
230 	 * if auditing on and process audit state not set,
231 	 * setup audit context for process.
232 	 */
233 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
234 		syslog(LOG_AUTH | LOG_ERR,
235 		    "pam_unix_cred: cannot create start audit session %m");
236 		return (PAM_SYSTEM_ERR);
237 	}
238 	adt_get_auid(ah, &auid);
239 	if (debug) {
240 		int	auditstate;
241 
242 		if (auditon(A_GETCOND, (caddr_t)&auditstate,
243 		    sizeof (auditstate)) != 0) {
244 			auditstate = AUC_DISABLED;
245 		}
246 		syslog(LOG_AUTH | LOG_DEBUG,
247 		    "pam_unix_cred: state = %d, auid = %d", auditstate,
248 		    auid);
249 	}
250 	if (getpwnam_r(user, &pwd, pwbuf, sizeof (pwbuf)) == NULL) {
251 		syslog(LOG_AUTH | LOG_ERR,
252 		    "pam_unix_cred: cannot get passwd entry for user = %s",
253 		    user);
254 		ret = PAM_USER_UNKNOWN;
255 		goto adt_done;
256 	}
257 
258 	if ((auid == AU_NOAUDITID) &&
259 	    (flags & PAM_ESTABLISH_CRED)) {
260 		struct passwd	apwd;
261 		char	apwbuf[NSS_BUFLEN_PASSWD];
262 
263 		errno = 0;
264 		if ((rhost == NULL || *rhost == '\0')) {
265 			if (adt_load_ttyname(tty, &termid) != 0) {
266 				if (errno == ENETDOWN) {
267 					/*
268 					 * tolerate not being able to
269 					 * translate local hostname
270 					 * to a termid -- it will be
271 					 * "loopback".
272 					 */
273 					syslog(LOG_AUTH | LOG_ERR,
274 					    "pam_unix_cred: cannot load "
275 					    "ttyname: %m, continuing.");
276 					goto adt_setuser;
277 				} else if (errno != 0) {
278 					syslog(LOG_AUTH | LOG_ERR,
279 					    "pam_unix_cred: cannot load "
280 					    "ttyname: %m.");
281 				} else {
282 					syslog(LOG_AUTH | LOG_ERR,
283 					    "pam_unix_cred: cannot load "
284 					    "ttyname.");
285 				}
286 				ret = PAM_SYSTEM_ERR;
287 				goto adt_done;
288 			}
289 		} else {
290 			if (adt_load_hostname(rhost, &termid) != 0) {
291 				if (errno != 0) {
292 					syslog(LOG_AUTH | LOG_ERR,
293 					    "pam_unix_cred: cannot load "
294 					    "hostname: %m.");
295 				} else {
296 					syslog(LOG_AUTH | LOG_ERR,
297 					    "pam_unix_cred: cannot load "
298 					    "hostname.");
299 				}
300 				ret = PAM_SYSTEM_ERR;
301 				goto adt_done;
302 			}
303 		}
304 adt_setuser:
305 		if ((auser != NULL) && (*auser != '\0') &&
306 		    (getpwnam_r(auser, &apwd, apwbuf,
307 		    sizeof (apwbuf)) != NULL)) {
308 			/*
309 			 * set up the initial audit for user coming
310 			 * from another user
311 			 */
312 			if (adt_set_user(ah, apwd.pw_uid, apwd.pw_gid,
313 			    apwd.pw_uid, apwd.pw_gid, termid, ADT_NEW) != 0) {
314 				syslog(LOG_AUTH | LOG_ERR,
315 				    "pam_unix_cred: cannot set auser audit "
316 				    "%m");
317 				ret = PAM_SYSTEM_ERR;
318 				goto adt_done;
319 			}
320 			if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid,
321 			    pwd.pw_uid, pwd.pw_gid, NULL,
322 			    ADT_UPDATE) != 0) {
323 				syslog(LOG_AUTH | LOG_ERR,
324 				    "pam_unix_cred: cannot merge user audit "
325 				    "%m");
326 				ret = PAM_SYSTEM_ERR;
327 				goto adt_done;
328 			}
329 			if (debug) {
330 				syslog(LOG_AUTH | LOG_DEBUG,
331 				    "pam_unix_cred: new audit set for %d:%d",
332 				    apwd.pw_uid, pwd.pw_uid);
333 			}
334 		} else {
335 			/*
336 			 * No authenticated user or authenticated user is
337 			 * not a local user, no remote attribution, set
338 			 * up the initial audit as for direct user login
339 			 */
340 			if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid,
341 			    pwd.pw_uid, pwd.pw_gid, termid, ADT_NEW) != 0) {
342 				syslog(LOG_AUTH | LOG_ERR,
343 				    "pam_unix_cred: cannot set user audit %m");
344 				ret = PAM_SYSTEM_ERR;
345 				goto adt_done;
346 			}
347 		}
348 		if (adt_set_proc(ah) != 0) {
349 			syslog(LOG_AUTH | LOG_ERR,
350 			    "pam_unix_cred: cannot set process audit %m");
351 			ret = PAM_CRED_ERR;
352 			goto adt_done;
353 		}
354 		if (debug) {
355 			syslog(LOG_AUTH | LOG_DEBUG,
356 			    "pam_unix_cred: new audit set for %d",
357 			    pwd.pw_uid);
358 		}
359 	} else if ((auid != AU_NOAUDITID) &&
360 	    (flags & PAM_REINITIALIZE_CRED)) {
361 		if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid, pwd.pw_uid,
362 		    pwd.pw_gid, NULL, ADT_UPDATE) != 0) {
363 			syslog(LOG_AUTH | LOG_ERR,
364 			    "pam_unix_cred: cannot set user audit %m");
365 			ret = PAM_SYSTEM_ERR;
366 			goto adt_done;
367 		}
368 		if (adt_set_proc(ah) != 0) {
369 			syslog(LOG_AUTH | LOG_ERR,
370 			    "pam_unix_cred: cannot set process audit %m");
371 			ret = PAM_CRED_ERR;
372 			goto adt_done;
373 		}
374 		if (debug) {
375 			syslog(LOG_AUTH | LOG_DEBUG,
376 			    "pam_unix_cred: audit merged for %d:%d",
377 			    auid, pwd.pw_uid);
378 		}
379 	} else if (debug) {
380 		syslog(LOG_AUTH | LOG_DEBUG,
381 		    "pam_unix_cred: audit already set for %d", auid);
382 	}
383 adt_done:
384 	if (termid != NULL)
385 		free(termid);
386 	if (adt_end_session(ah) != 0) {
387 		syslog(LOG_AUTH | LOG_ERR,
388 		    "pam_unix_cred: unable to end audit session");
389 	}
390 
391 	if (ret != PAM_SUCCESS)
392 		return (ret);
393 
394 	/* Initialize the user's project */
395 	(void) pam_get_item(pamh, PAM_RESOURCE, (void **)&kvs);
396 	if (kvs != NULL) {
397 		char *tmp, *lasts, *tok;
398 
399 		kvs = tmp = strdup(kvs);
400 		if (kvs == NULL)
401 			return (PAM_BUF_ERR);
402 
403 		while ((tok = strtok_r(tmp, ";", &lasts)) != NULL) {
404 			if (strncmp(tok, PROJECT, PROJSZ) == 0) {
405 				projname = tok + PROJSZ;
406 				break;
407 			}
408 			tmp = NULL;
409 		}
410 	} else {
411 		projname = NULL;
412 	}
413 
414 	if (projname == NULL || *projname == '\0') {
415 		pproj = getdefaultproj(user, &proj, (void *)&buf,
416 		    PROJECT_BUFSZ);
417 	} else {
418 		pproj = getprojbyname(projname, &proj, (void *)&buf,
419 		    PROJECT_BUFSZ);
420 	}
421 	/* projname points into kvs, so this is the first opportunity to free */
422 	if (kvs != NULL)
423 		free(kvs);
424 	if (pproj == NULL) {
425 		syslog(LOG_AUTH | LOG_ERR,
426 		    "pam_unix_cred: no default project for user %s", user);
427 		if (!nowarn) {
428 			(void) snprintf(messages[0], sizeof (messages[0]),
429 			    dgettext(TEXT_DOMAIN, "No default project!"));
430 			(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
431 			    1, messages, NULL);
432 		}
433 		return (PAM_SYSTEM_ERR);
434 	}
435 	if ((error = setproject(proj.pj_name, user, TASK_NORMAL)) != 0) {
436 		kva_t *kv_array;
437 
438 		switch (error) {
439 		case SETPROJ_ERR_TASK:
440 			if (errno == EAGAIN) {
441 				syslog(LOG_AUTH | LOG_ERR,
442 				    "pam_unix_cred: project \"%s\" resource "
443 				    "control limit has been reached",
444 				    proj.pj_name);
445 				(void) snprintf(messages[0],
446 				    sizeof (messages[0]), dgettext(
447 				    TEXT_DOMAIN,
448 				    "Resource control limit has been "
449 				    "reached"));
450 			} else {
451 				syslog(LOG_AUTH | LOG_ERR,
452 				    "pam_unix_cred: user %s could not join "
453 				    "project \"%s\": %m", user, proj.pj_name);
454 				(void) snprintf(messages[0],
455 				    sizeof (messages[0]), dgettext(
456 				    TEXT_DOMAIN,
457 				    "Could not join default project"));
458 			}
459 			if (!nowarn)
460 				(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1,
461 				    messages, NULL);
462 			break;
463 		case SETPROJ_ERR_POOL:
464 			(void) snprintf(messages[0], sizeof (messages[0]),
465 			    dgettext(TEXT_DOMAIN,
466 			    "Could not bind to resource pool"));
467 			switch (errno) {
468 			case EACCES:
469 				syslog(LOG_AUTH | LOG_ERR,
470 				    "pam_unix_cred: project \"%s\" could not "
471 				    "bind to resource pool: No resource pool "
472 				    "accepting default bindings exists",
473 				    proj.pj_name);
474 				(void) snprintf(messages[1],
475 				    sizeof (messages[1]),
476 				    dgettext(TEXT_DOMAIN,
477 				    "No resource pool accepting "
478 				    "default bindings exists"));
479 				break;
480 			case ESRCH:
481 				syslog(LOG_AUTH | LOG_ERR,
482 				    "pam_unix_cred: project \"%s\" could not "
483 				    "bind to resource pool: The resource pool "
484 				    "is unknown", proj.pj_name);
485 				(void) snprintf(messages[1],
486 				    sizeof (messages[1]),
487 				    dgettext(TEXT_DOMAIN,
488 				    "The specified resource pool "
489 				    "is unknown"));
490 				break;
491 			default:
492 				(void) snprintf(messages[1],
493 				    sizeof (messages[1]),
494 				    dgettext(TEXT_DOMAIN,
495 				    "Failure during pool binding"));
496 				syslog(LOG_AUTH | LOG_ERR,
497 				    "pam_unix_cred: project \"%s\" could not "
498 				    "bind to resource pool: %m", proj.pj_name);
499 			}
500 			if (!nowarn)
501 				(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
502 				    2, messages, NULL);
503 			break;
504 		default:
505 			/*
506 			 * Resource control assignment failed.  Unlike
507 			 * newtask(1m), we treat this as an error.
508 			 */
509 			if (error < 0) {
510 				/*
511 				 * This isn't supposed to happen, but in
512 				 * case it does, this error message
513 				 * doesn't use error as an index, like
514 				 * the others might.
515 				 */
516 				syslog(LOG_AUTH | LOG_ERR,
517 				    "pam_unix_cred: unkwown error joining "
518 				    "project \"%s\" (%d)", proj.pj_name, error);
519 				(void) snprintf(messages[0],
520 				    sizeof (messages[0]),
521 				    dgettext(TEXT_DOMAIN,
522 				    "unkwown error joining project \"%s\""
523 				    " (%d)"), proj.pj_name, error);
524 			} else if ((kv_array = _str2kva(proj.pj_attr, KV_ASSIGN,
525 			    KV_DELIMITER)) != NULL) {
526 				syslog(LOG_AUTH | LOG_ERR,
527 				    "pam_unix_cred: %s resource control "
528 				    "assignment failed for project \"%s\"",
529 				    kv_array->data[error - 1].key,
530 				    proj.pj_name);
531 				(void) snprintf(messages[0],
532 				    sizeof (messages[0]),
533 				    dgettext(TEXT_DOMAIN,
534 				    "%s resource control assignment failed for "
535 				    "project \"%s\""),
536 				    kv_array->data[error - 1].key,
537 				    proj.pj_name);
538 				_kva_free(kv_array);
539 			} else {
540 				syslog(LOG_AUTH | LOG_ERR,
541 				    "pam_unix_cred: resource control "
542 				    "assignment failed for project \"%s\""
543 				    "attribute %d", proj.pj_name, error);
544 				(void) snprintf(messages[0],
545 				    sizeof (messages[0]),
546 				    dgettext(TEXT_DOMAIN,
547 				    "resource control assignment failed for "
548 				    "project \"%s\" attribute %d"),
549 				    proj.pj_name, error);
550 			}
551 			if (!nowarn)
552 				(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
553 				    1, messages, NULL);
554 		}
555 		return (PAM_SYSTEM_ERR);
556 	}
557 
558 	ua = getusernam(user);
559 
560 	defp = defopen_r(AUTH_POLICY);
561 
562 	tset = def = lim = NULL;
563 
564 	if (getset(USERATTR_LIMPRIV_KW, DEF_LIMITPRIV, ua, &lim, defp) != 0 ||
565 	    getset(USERATTR_DFLTPRIV_KW, DEF_DFLTPRIV, ua, &def, defp) != 0) {
566 		ret = PAM_SYSTEM_ERR;
567 		goto out;
568 	}
569 
570 	if (def == NULL) {
571 		def = priv_str_to_set("basic", ",", NULL);
572 		errno = 0;
573 		if ((pathconf("/", _PC_CHOWN_RESTRICTED) == -1) && (errno == 0))
574 			(void) priv_addset(def, PRIV_FILE_CHOWN_SELF);
575 	}
576 	/*
577 	 * Silently limit the privileges to those actually available
578 	 * in the current zone.
579 	 */
580 	tset = priv_allocset();
581 	if (tset == NULL) {
582 		ret = PAM_SYSTEM_ERR;
583 		goto out;
584 	}
585 	if (getppriv(PRIV_PERMITTED, tset) != 0) {
586 		ret = PAM_SYSTEM_ERR;
587 		goto out;
588 	}
589 	if (!priv_issubset(def, tset))
590 		priv_intersect(tset, def);
591 	/*
592 	 * We set privilege awareness here so that I gets copied to
593 	 * P & E when the final setuid(uid) happens.
594 	 */
595 	(void) setpflags(PRIV_AWARE, 1);
596 	if (setppriv(PRIV_SET, PRIV_INHERITABLE, def) != 0) {
597 		syslog(LOG_AUTH | LOG_ERR,
598 		    "pam_setcred: setppriv(defaultpriv) failed: %m");
599 		ret = PAM_CRED_ERR;
600 	}
601 
602 	if (lim != NULL) {
603 		/*
604 		 * Silently limit the privileges to the limit set available.
605 		 */
606 		if (getppriv(PRIV_LIMIT, tset) != 0) {
607 			ret = PAM_SYSTEM_ERR;
608 			goto out;
609 		}
610 		if (!priv_issubset(lim, tset))
611 			priv_intersect(tset, lim);
612 		if (setppriv(PRIV_SET, PRIV_LIMIT, lim) != 0) {
613 			syslog(LOG_AUTH | LOG_ERR,
614 			    "pam_setcred: setppriv(limitpriv) failed: %m");
615 			ret = PAM_CRED_ERR;
616 			goto out;
617 		}
618 		/*
619 		 * In order not to surprise certain applications, we
620 		 * need to get rid of privilege awareness and thus we must
621 		 * set this flag which will cause a reset on set*uid().
622 		 */
623 		(void) setpflags(PRIV_AWARE_RESET, 1);
624 	}
625 	/*
626 	 * This may fail but we do not care as this will be reset later
627 	 * when the uids are set to their final values.
628 	 */
629 	(void) setpflags(PRIV_AWARE, 0);
630 
631 out:
632 	if (defp != NULL)
633 		defclose_r(defp);
634 
635 	if (ua != NULL)
636 		free_userattr(ua);
637 	if (lim != NULL)
638 		priv_freeset(lim);
639 	if (def != NULL)
640 		priv_freeset(def);
641 	if (tset != NULL)
642 		priv_freeset(tset);
643 
644 	return (ret);
645 }
646