2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: get_level.c /main/4 1995/10/27 16:19:39 rswiston $ */
27 * David Dolson June 7/92
28 * - rewrote most of B1 security routines. Much of it is based on
29 * parallel routines in login.
31 * - rolled the xdm version of this file into dtlogin.
34 #ifdef BLS /* Brackets entire file */
35 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
49 #include <sys/security.h>
50 #include <sys/audit.h>
53 #if defined(TAC3) && !defined(TPLOGIN)
54 #include <sys/secpolicy.h>
55 #include <mandatory.h>
60 #include <sys/ioctl.h>
70 * Local include file for bls specific definitions.
71 * Also defines some of the structures from dm.h for bls usage.
75 /* drop those privs from the base set which are not needed by xdm */
79 priv_t privs[SEC_SPRIVVEC_SIZE];
81 getpriv(SEC_BASE_PRIV, privs);
82 RMBIT(privs, SEC_ALLOWNETACCESS);
83 RMBIT(privs, SEC_NETPRIVSESSION);
84 RMBIT(privs, SEC_NETNOAUTH);
85 RMBIT(privs, SEC_MULTILEVELDIR);
86 setpriv(SEC_BASE_PRIV, privs);
90 /* stuff to do at the start */
94 /* set default file creation mode to be restrictive */
95 umask(~SEC_DEFAULT_MODE);
99 /* check that the requested security level is valid for this user,
100 * return 1 = success, return 0 is fail(fatal)
103 verify_user_seclevel( struct verify_info verify, char *desired_label)
106 mand_ir_t *dl_ir, *clearance_ir;
107 struct pr_passwd *prpwd;
110 prpwd = verify->prpwd;
114 /* check that desired_label falls within user's range */
115 dl_ir = mand_er_to_ir(desired_label);
117 audit_login(prpwd, pwd, verify->terminal,
118 "Unknown clearance level", ES_LOGIN_FAILED);
119 Debug("unable to translate clearance\n");
122 /* get user clearance from prpwd database */
123 if (prpwd->uflg.fg_clearance)
124 clearance_ir = &prpwd->ufld.fd_clearance;
125 else if (prpwd->sflg.fg_clearance)
126 clearance_ir = &prpwd->sfld.fd_clearance;
128 clearance_ir = mand_syslo;
130 /* make sure clearance dominates or equals desired_label */
131 switch(mand_ir_relationship(/* subject */ dl_ir,
132 /* object */ clearance_ir)) {
138 audit_login(prpwd, pwd, verify->terminal,
139 "Security label out of range", ES_LOGIN_FAILED);
140 Debug("Invalid clearance for this user\n");
144 verify->clearance_ir = clearance_ir;
145 verify->sec_label_ir = dl_ir;
150 /* check the proper structures to determine if the user has a password.
151 * If the nullpw field is set, the user does not need one, and this
152 * overrides the rest of the checking.
153 * return 1 means that a password exists (or is not needed)
156 password_exists(struct verify_info *verify)
158 struct pr_passwd *prpwd;
161 Debug("password_exists()\n");
162 prpwd = verify->prpwd;
163 if (prpwd->uflg.fg_nullpw)
164 nocheck=prpwd->ufld.fd_nullpw;
165 else if (prpwd->sflg.fg_nullpw)
166 nocheck=prpwd->sfld.fd_nullpw;
170 if (!nocheck) { /* user needs password */
171 Debug("password required for user\n");
172 if (!prpwd->uflg.fg_encrypt ||
173 prpwd->ufld.fd_encrypt[0] == '\0' ) {
181 /* check that the requested security level can be used on this X terminal,
182 * and that it is not locked.
183 * Currently there is no support for locking xterms like there is for
184 * /dev/tty* terminals.
187 verify_sec_xterm(struct verify_info *verify, char *desired_label)
193 /* set clearance and label for the user. Audit all failures.
194 * return 0=fail, 1=pass
197 set_sec_label(struct verify_info *verify)
199 struct pr_passwd *prpwd;
202 prpwd = verify->prpwd;
205 if (setclrnce(verify->sec_label_ir)==-1) {
208 audit_login(prpwd, pwd, verify->terminal,
209 "Insufficient privs to set clearance", ES_LOGIN_FAILED);
210 Debug ("login failed: EPERM on setclrnce()\n");
213 /* audit:login failed: xdm memory fault */
215 audit_login(prpwd, pwd, verify->terminal,
216 "Unable to set clearance", ES_LOGIN_FAILED);
217 Debug ("setclrnce failed: error: %d\n", errno);
223 if (setslabel(verify->sec_label_ir)==-1) {
226 audit_login(prpwd, pwd, verify->terminal,
227 "Insufficient privs to set sec label", ES_LOGIN_FAILED);
228 Debug ("login failed: insufficient priv. to setslabel()\n");
231 /* audit:login failed: xdm memory fault */
233 audit_login(prpwd, pwd, verify->terminal,
234 "Unable to set sec label", ES_LOGIN_FAILED);
235 Debug ("setslabel() failed: error: %d\n", errno);
243 /* set the effective, base, and maximum priv vectors for the
244 * new process, based on values from the pr_passwd entry.
245 * Inability to find either user priv's or default priv's
246 * results in failure. One or the other must be there.
247 * Function returns 1 for success, 0 for failure.
248 * A failure of this function should be considered fatal.
251 set_sec_privs(struct verify_info *verify)
254 priv_t *maxprivs, *bprivs;
255 priv_t curr_bprivs[SEC_SPRIVVEC_SIZE];
256 priv_t curr_sprivs[SEC_SPRIVVEC_SIZE];
258 struct pr_passwd *prpwd;
262 prpwd = verify->prpwd;
265 /* kernal authorizations */
266 if (prpwd->uflg.fg_sprivs) {
267 maxprivs = &prpwd->ufld.fd_sprivs[0];
268 }else if(prpwd->sflg.fg_sprivs) {
269 maxprivs = &prpwd->sfld.fd_sprivs[0];
270 Debug("Using default kernel priv's\n");
272 audit_login(prpwd, pwd, verify->terminal,
273 "Unable to find kernal priv set for user",
275 Debug("Can't find max. priv set for user-quitting\n");
279 /* base priv's and initial effective priv's */
280 if (verify->prpwd->uflg.fg_bprivs) {
281 bprivs = &verify->prpwd->ufld.fd_bprivs[0];
282 }else if (verify->prpwd->sflg.fg_bprivs) { /* use system defaults */
283 bprivs = &verify->prpwd->sfld.fd_bprivs[0];
284 Debug("Using default base priv's\n");
286 audit_login(prpwd, pwd, verify->terminal,
287 "Unable to find base priv set for user",
289 Debug("Can't find base priv set for user-quitting\n");
293 getpriv(SEC_MAXIMUM_PRIV, curr_sprivs);
294 getpriv(SEC_BASE_PRIV, curr_bprivs);
296 /* remove those privs which the current process does not have,
297 * to avoid any error in the following system calls
299 for (bit=0; bit<=SEC_MAX_SPRIV; bit++) {
300 if (!ISBITSET(curr_sprivs, bit))
301 RMBIT(maxprivs, bit);
302 if (!ISBITSET(curr_bprivs, bit))
306 /* login removes those bits from maxprivs which the current process
307 * does not have. - This program assumes the system config
308 * utilities will enforce the rules for setpriv(3). Any failure
309 * of setpriv will indicate a corrupt database.
312 if (setpriv(SEC_MAXIMUM_PRIV, maxprivs)==-1) {
315 Debug("setpriv (max) failed: EPERM\n");
318 Debug("setpriv (max) failed: EINVAL\n");
321 Debug("setpriv (max) failed: EFAULT\n");
324 Debug("setpriv (max) failed for unknown error: %d\n",errno);
327 audit_login(prpwd, pwd, verify->terminal,
328 "Unable to set Kernal privs", ES_LOGIN_FAILED);
329 Debug("Unable to set Kernal privs (error %d): aborting\n",errno);
333 if (setpriv(SEC_BASE_PRIV, bprivs)==-1) {
336 Debug("setpriv (base) failed: EPERM\n");
339 Debug("setpriv (base) failed: EINVAL\n");
342 Debug("setpriv (base) failed: EFAULT\n");
345 Debug("setpriv (base) failed for unknown error: %d\n",errno);
348 audit_login(prpwd, pwd, verify->terminal,
349 "Unable to set base privs", ES_LOGIN_FAILED);
353 if (setpriv(SEC_EFFECTIVE_PRIV, bprivs)==-1) {
356 Debug("setpriv (effective) failed: EPERM\n");
359 Debug("setpriv (effective) failed: EINVAL\n");
362 Debug("setpriv (effective) failed: EFAULT\n");
365 Debug("setpriv (effective) failed for unknown error: %d\n",
369 audit_login(prpwd, pwd, verify->terminal,
370 "Unable to set effective privs", ES_LOGIN_FAILED);
371 Debug("Unable to set effective privs (error %d): aborting\n",errno);
379 /* change the current process over to be owned by the user verify->uid.
380 * Also properly set the privs, sec label, etc.
381 * Also audits failures.
382 * return=1 for success, 0 for fail. A failure should be considered fatal.
385 change_to_user(struct verify_info *verify)
387 struct pr_passwd *prpwd;
391 prpwd = verify->prpwd;
394 Debug("change_to_user()\n");
395 /* 1. set the login user id - settable only once */
396 if (setluid(verify->uid)==-1) {
399 Debug("Unable to set luid - EPERM\n");
400 audit_login(prpwd, pwd, verify->terminal,
401 "Unable to set luid - insufficient privs",
405 Debug("Unable to set luid - suspicious of pwd db.\n");
406 audit_login(prpwd, pwd, verify->terminal,
407 "Unable to set luid - out of range", ES_LOGIN_FAILED);
410 Debug("Can't set luid-Unknown error %d\n",errno);
411 audit_login(prpwd, pwd, verify->terminal,
412 "Unable to set luid-unknown error", ES_LOGIN_FAILED);
419 * Set the 'nice' priority if necessary. Since the return value
420 * of nice(2) can normally be -1 from the documentation, and
421 * -1 is the error condition, we key off of errno, not the
422 * return value to find if the change were successful.
423 * Note we must do this before the setuid(2) below.
426 prpwd = verify->prpwd;
427 if (prpwd->uflg.fg_nice)
428 new_nice = prpwd->ufld.fd_nice;
429 else if (prpwd->sflg.fg_nice)
430 new_nice = prpwd->sfld.fd_nice;
432 if (prpwd->uflg.fg_nice || prpwd->sflg.fg_nice) {
433 (void) nice(new_nice);
435 audit_login(prpwd, verify->pwd, NULL,
436 "bad 'nice' setting", ES_LOGIN_FAILED);
437 Debug("Bad priority setting.\n");
443 /* 2. set the group(s) id and
444 * 3. set the regular user id */
448 /* setgroups (verify->ngroups, verify->groups);
450 if(setgid (verify->groups[0])) {
453 Debug("setgid EPERM\n");
456 Debug("setgid EINVAL\n");
459 Debug("setgid unknown error: %d\n",errno);
464 initgroups(verify->user_name, verify->groups[0]);
466 if(setgid (verify->gid)) {
468 case EPERM: Debug("setgid EPERM\n");break;
469 case EINVAL: Debug("setgid EINVAL\n");break;
470 default: Debug("setgid unknown error\n");break;
476 if(setuid (verify->uid)) {
478 case EPERM: Debug("setgid EPERM\n");break;
479 case EINVAL: Debug("setgid EINVAL\n");break;
480 default: Debug("setgid unknown error\n");break;
485 /* 4. set security clearance and label for the new process */
486 if (!set_sec_label(verify))
489 /* 5. set audit parameters */
490 audit_adjust_mask(prpwd);
492 /* 6. set privlege levels - maximum, base, and effective */
493 if (!set_sec_privs(verify))
501 * Try to read back everything, and print it. If a fatal error occurs,
502 * return code is 0. 1=success.
505 dump_sec_debug_info(struct verify_info *verify)
508 priv_t privs[SEC_SPRIVVEC_SIZE];
510 Debug ("luid: %d, real uid: %d, effective uid:%d,\n",
511 getluid(),getuid(),geteuid());
512 Debug ("real gid:%d, effective gid: %d\n", getgid(),getegid());
513 level_ir = mand_alloc_ir();
514 if (getclrnce(level_ir)==-1) {
516 case EFAULT: Debug("getclrnce EFAULT\n");break;
517 case EINVAL: Debug("getclrnce EINVAL\n");break;
518 default: Debug("getclrnce unknown error:%d\n",errno);break;
521 }else Debug ("Clearance: %s\n", mand_ir_to_er(level_ir) );
522 if (getslabel(level_ir)==-1) {
524 case EFAULT: Debug("getslabel EFAULT\n");break;
525 case EINVAL: Debug("getslabel EINVAL\n");break;
526 default: Debug("getslabel unknown error:%d\n",errno);break;
529 }else Debug ("Level: %s\n", mand_ir_to_er(level_ir));
530 mand_free_ir(level_ir);
531 if(getpriv(SEC_MAXIMUM_PRIV, privs)==-1) {
533 case EFAULT: Debug("getpriv max EFAULT\n");break;
534 case EINVAL: Debug("getpriv max EINVAL\n");break;
535 default: Debug("getpriv max unknown error:%d\n",errno);
539 }else Debug ("max priv: %x.%x\n", privs[0],privs[1]);
540 if(getpriv(SEC_EFFECTIVE_PRIV, privs)==-1) {
542 case EFAULT: Debug("getpriv eff EFAULT\n");break;
543 case EINVAL: Debug("getpriv eff EINVAL\n");break;
544 default: Debug("getpriv eff unknown error:%d\n",errno);
548 }else Debug ("eff priv: %x.%x\n", privs[0],privs[1]);
549 if(getpriv(SEC_BASE_PRIV, privs)==-1) {
551 case EFAULT: Debug("getpriv base EFAULT\n");break;
552 case EINVAL: Debug("getpriv base EINVAL\n");break;
553 default: Debug("getpriv base unknown error:%d\n",errno);
557 }else Debug ("base priv: %x.%x\n", privs[0],privs[1]);
563 * Input: file name string (ex. $HOME/.dtlogininfo)
564 * verify structure with password stuff
565 * Write login information to a file to be displayed later, after a
568 * Xsession will need to be modified something like this...
569 * DTHELLO="$DTDIR/bin/dthello -f /etc/copyright -f $HOME/.dtlogininfo"
573 writeLoginInfo( char *filename, struct verify_info *verify)
575 char *s1="Last successful login: %s";
576 char *s2="Last unsuccessful login: %s";
581 char *message="Sensitivity level for process: ";
584 time_t slogin, ulogin;
586 char *uterminal, *sterminal;
590 Debug("Writing login info\n");
591 if ((fp = fopen (filename, "w")) == 0 )
594 if (verify->prpwd->uflg.fg_slogin)
595 slogin=verify->prpwd->ufld.fd_slogin;
599 if (verify->prpwd->uflg.fg_ulogin)
600 ulogin=verify->prpwd->ufld.fd_ulogin;
604 if (verify->prpwd->uflg.fg_suctty)
605 sterminal=verify->prpwd->ufld.fd_suctty;
609 if (verify->prpwd->uflg.fg_unsuctty)
610 uterminal=verify->prpwd->ufld.fd_unsuctty;
614 slabel = mand_ir_to_er(verify->sec_label_ir);
616 fprintf(fp,"-----------------------------------\n");
617 fprintf(fp,"\nPrevious login information:\n\n");
619 /* tricky formatting */
621 sprintf(s, s1, ctime(&slogin));
623 s[nl]='\0'; /* remove new-line */
625 sprintf(s,s1,"NEVER");
628 strncpy(term, sterminal, 14);
631 fprintf(fp,"%s\n",s);
634 sprintf(s, s2, ctime(&ulogin));
636 s[nl]='\0'; /* remove new-line */
638 sprintf(s,s2,"NEVER");
641 strncpy(term, uterminal, 14);
644 fprintf(fp,"%s\n",s);
646 label = (char*)malloc(strlen(message)+strlen(slabel)+1);
647 sprintf(label, "%s%s", message, slabel);
648 if (strlen (label) > 77) {
649 for(i=75; label[i]!=',' && i>0; i--);
650 if (i==0) for(i=75; label[i]!=' ' && i>0; i--);
652 strncpy(s, label, i+1);
654 fprintf(fp,"%s\n",s);
655 strncpy(s, &label[i+1], 75);
657 fprintf(fp,"%s\n",s);
659 fprintf(fp,"%s\n",label);