123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- /* $XConsortium: get_level.c /main/4 1995/10/27 16:19:39 rswiston $ */
- /*
- * get_level.c
- * last modified by:
- * David Dolson June 7/92
- * - rewrote most of B1 security routines. Much of it is based on
- * parallel routines in login.
- * Ron Voll July 7/92
- * - rolled the xdm version of this file into dtlogin.
- */
- #ifdef BLS /* Brackets entire file */
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <signal.h>
- #include <pwd.h>
- #include <grp.h>
- #include <stdio.h>
- #include <termio.h>
- #include <errno.h>
- #ifdef SEC_NET_TTY
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #endif
- #include <sys/security.h>
- #include <sys/audit.h>
- #include <prot.h>
- #include <protcmd.h>
- #if defined(TAC3) && !defined(TPLOGIN)
- #include <sys/secpolicy.h>
- #include <mandatory.h>
- #include <fcntl.h>
- #endif
- #include <stdlib.h>
- #include <time.h>
- #include <sys/ioctl.h>
- #include <unistd.h>
- #include <string.h>
- #if 0
- #include <strings.h>
- #endif
- #include <sys/wait.h>
- #include <grp.h>
- /*
- * Local include file for bls specific definitions.
- * Also defines some of the structures from dm.h for bls usage.
- */
- #include "bls.h"
- /* drop those privs from the base set which are not needed by xdm */
- void
- drop_privs(void)
- {
- priv_t privs[SEC_SPRIVVEC_SIZE];
- getpriv(SEC_BASE_PRIV, privs);
- RMBIT(privs, SEC_ALLOWNETACCESS);
- RMBIT(privs, SEC_NETPRIVSESSION);
- RMBIT(privs, SEC_NETNOAUTH);
- RMBIT(privs, SEC_MULTILEVELDIR);
- setpriv(SEC_BASE_PRIV, privs);
- return;
- }
- /* stuff to do at the start */
- void
- init_security(void)
- {
- /* set default file creation mode to be restrictive */
- umask(~SEC_DEFAULT_MODE);
- drop_privs();
- }
- /* check that the requested security level is valid for this user,
- * return 1 = success, return 0 is fail(fatal)
- */
- int
- verify_user_seclevel( struct verify_info verify, char *desired_label)
- {
- int uid;
- mand_ir_t *dl_ir, *clearance_ir;
- struct pr_passwd *prpwd;
- struct passwd *pwd;
- prpwd = verify->prpwd;
- pwd = verify->pwd;
- uid = verify->uid;
- /* check that desired_label falls within user's range */
- dl_ir = mand_er_to_ir(desired_label);
- if (dl_ir ==NULL) {
- audit_login(prpwd, pwd, verify->terminal,
- "Unknown clearance level", ES_LOGIN_FAILED);
- Debug("unable to translate clearance\n");
- return 0;
- }
- /* get user clearance from prpwd database */
- if (prpwd->uflg.fg_clearance)
- clearance_ir = &prpwd->ufld.fd_clearance;
- else if (prpwd->sflg.fg_clearance)
- clearance_ir = &prpwd->sfld.fd_clearance;
- else
- clearance_ir = mand_syslo;
- /* make sure clearance dominates or equals desired_label */
- switch(mand_ir_relationship(/* subject */ dl_ir,
- /* object */ clearance_ir)) {
- case MAND_ODOM:
- case MAND_EQUAL:
- /* Within range */
- break;
- default:
- audit_login(prpwd, pwd, verify->terminal,
- "Security label out of range", ES_LOGIN_FAILED);
- Debug("Invalid clearance for this user\n");
- mand_free_ir(dl_ir);
- return 0;
- }
- verify->clearance_ir = clearance_ir;
- verify->sec_label_ir = dl_ir;
- return 1;
- }
- /* check the proper structures to determine if the user has a password.
- * If the nullpw field is set, the user does not need one, and this
- * overrides the rest of the checking.
- * return 1 means that a password exists (or is not needed)
- */
- int
- password_exists(struct verify_info *verify)
- {
- struct pr_passwd *prpwd;
- BOOL nocheck;
- Debug("password_exists()\n");
- prpwd = verify->prpwd;
- if (prpwd->uflg.fg_nullpw)
- nocheck=prpwd->ufld.fd_nullpw;
- else if (prpwd->sflg.fg_nullpw)
- nocheck=prpwd->sfld.fd_nullpw;
- else
- nocheck=FALSE;
- if (!nocheck) { /* user needs password */
- Debug("password required for user\n");
- if (!prpwd->uflg.fg_encrypt ||
- prpwd->ufld.fd_encrypt[0] == '\0' ) {
- return 0;
- }
- }
- return 1;
- }
- /* check that the requested security level can be used on this X terminal,
- * and that it is not locked.
- * Currently there is no support for locking xterms like there is for
- * /dev/tty* terminals.
- */
- int
- verify_sec_xterm(struct verify_info *verify, char *desired_label)
- {
- return 1;
- }
- /* set clearance and label for the user. Audit all failures.
- * return 0=fail, 1=pass
- */
- int
- set_sec_label(struct verify_info *verify)
- {
- struct pr_passwd *prpwd;
- struct passwd *pwd;
- /* set clearance */
- prpwd = verify->prpwd;
- pwd = verify->pwd;
- if (setclrnce(verify->sec_label_ir)==-1) {
- switch(errno) {
- case EPERM:
- audit_login(prpwd, pwd, verify->terminal,
- "Insufficient privs to set clearance", ES_LOGIN_FAILED);
- Debug ("login failed: EPERM on setclrnce()\n");
- break;
- case EFAULT:
- /* audit:login failed: xdm memory fault */
- default:
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to set clearance", ES_LOGIN_FAILED);
- Debug ("setclrnce failed: error: %d\n", errno);
- break;
- }
- return 0;
- }
- /* set label */
- if (setslabel(verify->sec_label_ir)==-1) {
- switch(errno) {
- case EPERM:
- audit_login(prpwd, pwd, verify->terminal,
- "Insufficient privs to set sec label", ES_LOGIN_FAILED);
- Debug ("login failed: insufficient priv. to setslabel()\n");
- break;
- case EFAULT:
- /* audit:login failed: xdm memory fault */
- default:
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to set sec label", ES_LOGIN_FAILED);
- Debug ("setslabel() failed: error: %d\n", errno);
- break;
- }
- return 0;
- }
- return 1;
- }
- /* set the effective, base, and maximum priv vectors for the
- * new process, based on values from the pr_passwd entry.
- * Inability to find either user priv's or default priv's
- * results in failure. One or the other must be there.
- * Function returns 1 for success, 0 for failure.
- * A failure of this function should be considered fatal.
- */
- int
- set_sec_privs(struct verify_info *verify)
- {
- priv_t *maxprivs, *bprivs;
- priv_t curr_bprivs[SEC_SPRIVVEC_SIZE];
- priv_t curr_sprivs[SEC_SPRIVVEC_SIZE];
- struct pr_passwd *prpwd;
- struct passwd *pwd;
- int bit;
- prpwd = verify->prpwd;
- pwd = verify->pwd;
- /* kernel authorizations */
- if (prpwd->uflg.fg_sprivs) {
- maxprivs = &prpwd->ufld.fd_sprivs[0];
- }else if(prpwd->sflg.fg_sprivs) {
- maxprivs = &prpwd->sfld.fd_sprivs[0];
- Debug("Using default kernel priv's\n");
- }else {
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to find kernel priv set for user",
- ES_LOGIN_FAILED);
- Debug("Can't find max. priv set for user-quitting\n");
- return 0;
- }
- /* base priv's and initial effective priv's */
- if (verify->prpwd->uflg.fg_bprivs) {
- bprivs = &verify->prpwd->ufld.fd_bprivs[0];
- }else if (verify->prpwd->sflg.fg_bprivs) { /* use system defaults */
- bprivs = &verify->prpwd->sfld.fd_bprivs[0];
- Debug("Using default base priv's\n");
- }else{
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to find base priv set for user",
- ES_LOGIN_FAILED);
- Debug("Can't find base priv set for user-quitting\n");
- return 0;
- }
- getpriv(SEC_MAXIMUM_PRIV, curr_sprivs);
- getpriv(SEC_BASE_PRIV, curr_bprivs);
- /* remove those privs which the current process does not have,
- * to avoid any error in the following system calls
- */
- for (bit=0; bit<=SEC_MAX_SPRIV; bit++) {
- if (!ISBITSET(curr_sprivs, bit))
- RMBIT(maxprivs, bit);
- if (!ISBITSET(curr_bprivs, bit))
- RMBIT(bprivs, bit);
- }
-
- /* login removes those bits from maxprivs which the current process
- * does not have. - This program assumes the system config
- * utilities will enforce the rules for setpriv(3). Any failure
- * of setpriv will indicate a corrupt database.
- */
- if (setpriv(SEC_MAXIMUM_PRIV, maxprivs)==-1) {
- switch(errno) {
- case EPERM:
- Debug("setpriv (max) failed: EPERM\n");
- break;
- case EINVAL:
- Debug("setpriv (max) failed: EINVAL\n");
- break;
- case EFAULT:
- Debug("setpriv (max) failed: EFAULT\n");
- break;
- default:
- Debug("setpriv (max) failed for unknown error: %d\n",errno);
- break;
- }
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to set Kernel privs", ES_LOGIN_FAILED);
- Debug("Unable to set Kernel privs (error %d): aborting\n",errno);
- return 0;
- }
- if (setpriv(SEC_BASE_PRIV, bprivs)==-1) {
- switch(errno) {
- case EPERM:
- Debug("setpriv (base) failed: EPERM\n");
- break;
- case EINVAL:
- Debug("setpriv (base) failed: EINVAL\n");
- break;
- case EFAULT:
- Debug("setpriv (base) failed: EFAULT\n");
- break;
- default:
- Debug("setpriv (base) failed for unknown error: %d\n",errno);
- break;
- }
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to set base privs", ES_LOGIN_FAILED);
- return 0;
- }
- if (setpriv(SEC_EFFECTIVE_PRIV, bprivs)==-1) {
- switch(errno) {
- case EPERM:
- Debug("setpriv (effective) failed: EPERM\n");
- break;
- case EINVAL:
- Debug("setpriv (effective) failed: EINVAL\n");
- break;
- case EFAULT:
- Debug("setpriv (effective) failed: EFAULT\n");
- break;
- default:
- Debug("setpriv (effective) failed for unknown error: %d\n",
- errno);
- break;
- }
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to set effective privs", ES_LOGIN_FAILED);
- Debug("Unable to set effective privs (error %d): aborting\n",errno);
- return 0;
- }
- return 1;
- }
- /* change the current process over to be owned by the user verify->uid.
- * Also properly set the privs, sec label, etc.
- * Also audits failures.
- * return=1 for success, 0 for fail. A failure should be considered fatal.
- */
- int
- change_to_user(struct verify_info *verify)
- {
- struct pr_passwd *prpwd;
- struct passwd *pwd;
- int new_nice;
- prpwd = verify->prpwd;
- pwd = verify->pwd;
- Debug("change_to_user()\n");
- /* 1. set the login user id - settable only once */
- if (setluid(verify->uid)==-1) {
- switch(errno) {
- case EPERM:
- Debug("Unable to set luid - EPERM\n");
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to set luid - insufficient privs",
- ES_LOGIN_FAILED);
- break;
- case EINVAL:
- Debug("Unable to set luid - suspicious of pwd db.\n");
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to set luid - out of range", ES_LOGIN_FAILED);
- break;
- default:
- Debug("Can't set luid-Unknown error %d\n",errno);
- audit_login(prpwd, pwd, verify->terminal,
- "Unable to set luid-unknown error", ES_LOGIN_FAILED);
- break;
- }
- return 0;
- }
- /*
- * Set the 'nice' priority if necessary. Since the return value
- * of nice(2) can normally be -1 from the documentation, and
- * -1 is the error condition, we key off of errno, not the
- * return value to find if the change were successful.
- * Note we must do this before the setuid(2) below.
- */
- errno = 0;
- prpwd = verify->prpwd;
- if (prpwd->uflg.fg_nice)
- new_nice = prpwd->ufld.fd_nice;
- else if (prpwd->sflg.fg_nice)
- new_nice = prpwd->sfld.fd_nice;
- if (prpwd->uflg.fg_nice || prpwd->sflg.fg_nice) {
- (void) nice(new_nice);
- if (errno != 0) {
- audit_login(prpwd, verify->pwd, NULL,
- "bad 'nice' setting", ES_LOGIN_FAILED);
- Debug("Bad priority setting.\n");
- return 0;
- }
- }
- /* 2. set the group(s) id and
- * 3. set the regular user id */
- #ifdef NGROUPS
- /* setgroups (verify->ngroups, verify->groups);
- */
- if(setgid (verify->groups[0])) {
- switch(errno) {
- case EPERM:
- Debug("setgid EPERM\n");
- break;
- case EINVAL:
- Debug("setgid EINVAL\n");
- break;
- default:
- Debug("setgid unknown error: %d\n",errno);
- break;
- }
- return 0;
- }
- initgroups(verify->user_name, verify->groups[0]);
- #else
- if(setgid (verify->gid)) {
- switch(errno) {
- case EPERM: Debug("setgid EPERM\n");break;
- case EINVAL: Debug("setgid EINVAL\n");break;
- default: Debug("setgid unknown error\n");break;
- }
- return 0;
- }
- #endif
- if(setuid (verify->uid)) {
- switch(errno) {
- case EPERM: Debug("setgid EPERM\n");break;
- case EINVAL: Debug("setgid EINVAL\n");break;
- default: Debug("setgid unknown error\n");break;
- }
- return 0;
- }
- /* 4. set security clearance and label for the new process */
- if (!set_sec_label(verify))
- return 0;
- /* 5. set audit parameters */
- audit_adjust_mask(prpwd);
- /* 6. set privlege levels - maximum, base, and effective */
- if (!set_sec_privs(verify))
- return 0;
- return 1;
- }
- /*
- * Try to read back everything, and print it. If a fatal error occurs,
- * return code is 0. 1=success.
- */
- int
- dump_sec_debug_info(struct verify_info *verify)
- {
- mand_ir_t *level_ir;
- priv_t privs[SEC_SPRIVVEC_SIZE];
- Debug ("luid: %d, real uid: %d, effective uid:%d,\n",
- getluid(),getuid(),geteuid());
- Debug ("real gid:%d, effective gid: %d\n", getgid(),getegid());
- level_ir = mand_alloc_ir();
- if (getclrnce(level_ir)==-1) {
- switch(errno) {
- case EFAULT: Debug("getclrnce EFAULT\n");break;
- case EINVAL: Debug("getclrnce EINVAL\n");break;
- default: Debug("getclrnce unknown error:%d\n",errno);break;
- }
- return 0;
- }else Debug ("Clearance: %s\n", mand_ir_to_er(level_ir) );
- if (getslabel(level_ir)==-1) {
- switch(errno) {
- case EFAULT: Debug("getslabel EFAULT\n");break;
- case EINVAL: Debug("getslabel EINVAL\n");break;
- default: Debug("getslabel unknown error:%d\n",errno);break;
- }
- return 0;
- }else Debug ("Level: %s\n", mand_ir_to_er(level_ir));
- mand_free_ir(level_ir);
- if(getpriv(SEC_MAXIMUM_PRIV, privs)==-1) {
- switch(errno) {
- case EFAULT: Debug("getpriv max EFAULT\n");break;
- case EINVAL: Debug("getpriv max EINVAL\n");break;
- default: Debug("getpriv max unknown error:%d\n",errno);
- break;
- }
- return 0;
- }else Debug ("max priv: %x.%x\n", privs[0],privs[1]);
- if(getpriv(SEC_EFFECTIVE_PRIV, privs)==-1) {
- switch(errno) {
- case EFAULT: Debug("getpriv eff EFAULT\n");break;
- case EINVAL: Debug("getpriv eff EINVAL\n");break;
- default: Debug("getpriv eff unknown error:%d\n",errno);
- break;
- }
- return 0;
- }else Debug ("eff priv: %x.%x\n", privs[0],privs[1]);
- if(getpriv(SEC_BASE_PRIV, privs)==-1) {
- switch(errno) {
- case EFAULT: Debug("getpriv base EFAULT\n");break;
- case EINVAL: Debug("getpriv base EINVAL\n");break;
- default: Debug("getpriv base unknown error:%d\n",errno);
- break;
- }
- return 0;
- }else Debug ("base priv: %x.%x\n", privs[0],privs[1]);
- return 1;
- }
- /*
- * writeLoginInfo
- * Input: file name string (ex. $HOME/.dtlogininfo)
- * verify structure with password stuff
- * Write login information to a file to be displayed later, after a
- * successful login.
- *
- * Xsession will need to be modified something like this...
- * DTHELLO="$DTDIR/bin/dthello -f /etc/copyright -f $HOME/.dtlogininfo"
- */
-
- int
- writeLoginInfo( char *filename, struct verify_info *verify)
- {
- char *s1="Last successful login: %s";
- char *s2="Last unsuccessful login: %s";
- char *s3;
- char s[80];
- char term[15];
- char *label;
- char *message="Sensitivity level for process: ";
- int i;
- int nl;
- time_t slogin, ulogin;
- char *slabel;
- char *uterminal, *sterminal;
-
- FILE *fp;
-
- Debug("Writing login info\n");
- if ((fp = fopen (filename, "w")) == 0 )
- return 0;
- if (verify->prpwd->uflg.fg_slogin)
- slogin=verify->prpwd->ufld.fd_slogin;
- else
- slogin=(time_t)0;
- if (verify->prpwd->uflg.fg_ulogin)
- ulogin=verify->prpwd->ufld.fd_ulogin;
- else
- ulogin=(time_t)0;
- if (verify->prpwd->uflg.fg_suctty)
- sterminal=verify->prpwd->ufld.fd_suctty;
- else
- sterminal="UNKNOWN";
- if (verify->prpwd->uflg.fg_unsuctty)
- uterminal=verify->prpwd->ufld.fd_unsuctty;
- else
- uterminal="UNKNOWN";
- slabel = mand_ir_to_er(verify->sec_label_ir);
- fprintf(fp,"-----------------------------------\n");
- fprintf(fp,"\nPrevious login information:\n\n");
- /* tricky formatting */
- if (slogin != 0) {
- sprintf(s, s1, ctime(&slogin));
- nl=strlen(s)-1;
- s[nl]='\0'; /* remove new-line */
- }else{
- sprintf(s,s1,"NEVER");
- }
- strcat(s, " from ");
- strncpy(term, sterminal, 14);
- term[14]='\0';
- strcat(s, term);
- fprintf(fp,"%s\n",s);
- if (ulogin != 0) {
- sprintf(s, s2, ctime(&ulogin));
- nl=strlen(s)-1;
- s[nl]='\0'; /* remove new-line */
- }else{
- sprintf(s,s2,"NEVER");
- }
- strcat(s, " from ");
- strncpy(term, uterminal, 14);
- term[14]='\0';
- strcat(s, term);
- fprintf(fp,"%s\n",s);
- label = (char*)malloc(strlen(message)+strlen(slabel)+1);
- sprintf(label, "%s%s", message, slabel);
- if (strlen (label) > 77) {
- for(i=75; label[i]!=',' && i>0; i--);
- if (i==0) for(i=75; label[i]!=' ' && i>0; i--);
- if (i==0) i=75;
- strncpy(s, label, i+1);
- s[i+1]='\0';
- fprintf(fp,"%s\n",s);
- strncpy(s, &label[i+1], 75);
- s[75]='\0';
- fprintf(fp,"%s\n",s);
- }else{
- fprintf(fp,"%s\n",label);
- }
-
- fclose(fp);
- return 1;
- }
- #endif /* BLS */
|