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