Path: blob/main/crypto/krb5/src/clients/ksu/authorization.c
34907 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/*2* Copyright (c) 1994 by the University of Southern California3*4* EXPORT OF THIS SOFTWARE from the United States of America may5* require a specific license from the United States Government.6* It is the responsibility of any person or organization contemplating7* export to obtain such a license before exporting.8*9* WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute10* this software and its documentation in source and binary forms is11* hereby granted, provided that any documentation or other materials12* related to such distribution or use acknowledge that the software13* was developed by the University of Southern California.14*15* DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The16* University of Southern California MAKES NO REPRESENTATIONS OR17* WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not18* limitation, the University of Southern California MAKES NO19* REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY20* PARTICULAR PURPOSE. The University of Southern21* California shall not be held liable for any liability nor for any22* direct, indirect, or consequential damages with respect to any23* claim by the user or distributor of the ksu software.24*25* KSU was written by: Ari Medvinsky, [email protected]26*/2728#include "ksu.h"2930static void31free_fcmd_list(char **list)32{33size_t i;3435if (list == NULL)36return;37for (i = 0; i < MAX_CMD && list[i] != NULL; i++)38free(list[i]);39free(list);40}4142krb5_boolean43fowner(FILE *fp, uid_t uid)44{45struct stat sbuf;4647/*48* For security reasons, file must be owned either by49* the user himself, or by root. Otherwise, don't grant access.50*/51if (fstat(fileno(fp), &sbuf)) {52return(FALSE);53}5455if ((sbuf.st_uid != uid) && sbuf.st_uid) {56return(FALSE);57}5859return(TRUE);60}6162/*63* Given a Kerberos principal "principal", and a local username "luser",64* determine whether user is authorized to login according to the authorization65* files ~luser/.k5login" and ~luser/.k5users. Set *ok to TRUE if authorized,66* FALSE if not authorized. Return 0 if the authorization check succeeded67* (regardless of its result), non-zero if it encountered an error.68*/6970krb5_error_code71krb5_authorization(krb5_context context, krb5_principal principal,72const char *luser, char *cmd, krb5_boolean *ok,73char **out_fcmd)74{75struct passwd *pwd;76char *princname = NULL;77int k5login_flag =0;78int k5users_flag =0;79krb5_boolean retbool =FALSE;80FILE * login_fp = 0, * users_fp = 0;81krb5_error_code retval = 0;82struct stat st_temp;8384*ok =FALSE;8586/* no account => no access */87if ((pwd = getpwnam(luser)) == NULL)88goto cleanup;8990retval = krb5_unparse_name(context, principal, &princname);91if (retval)92return retval;9394#ifdef DEBUG95printf("principal to be authorized %s\n", princname);96printf("login file: %s\n", k5login_path);97printf("users file: %s\n", k5users_path);98#endif99100k5login_flag = stat(k5login_path, &st_temp);101k5users_flag = stat(k5users_path, &st_temp);102103/* k5login and k5users must be owned by target user or root */104if (!k5login_flag){105login_fp = fopen(k5login_path, "r");106if (login_fp == NULL)107goto cleanup;108if (fowner(login_fp, pwd->pw_uid) == FALSE)109goto cleanup;110}111112if (!k5users_flag){113users_fp = fopen(k5users_path, "r");114if (users_fp == NULL)115goto cleanup;116if (fowner(users_fp, pwd->pw_uid) == FALSE)117goto cleanup;118}119120if (auth_debug){121fprintf(stderr,122"In krb5_authorization: if auth files exist -> can access\n");123}124125/* if either file exists,126first see if the principal is in the login in file,127if it's not there check the k5users file */128129if (!k5login_flag){130if (auth_debug)131fprintf(stderr,132"In krb5_authorization: principal to be authorized %s\n",133princname);134135retval = k5login_lookup(login_fp, princname, &retbool);136if (retval)137goto cleanup;138if (retbool) {139if (cmd)140*out_fcmd = xstrdup(cmd);141}142}143144if ((!k5users_flag) && (retbool == FALSE) ){145retval = k5users_lookup (users_fp, princname,146cmd, &retbool, out_fcmd);147if (retval)148goto cleanup;149}150151if (k5login_flag && k5users_flag){152153char * kuser = (char *) xcalloc (strlen(princname), sizeof(char));154if (!(krb5_aname_to_localname(context, principal,155strlen(princname), kuser))156&& (strcmp(kuser, luser) == 0)) {157retbool = TRUE;158}159160free(kuser);161}162163*ok =retbool;164165cleanup:166if (users_fp != NULL)167fclose(users_fp);168if (login_fp != NULL)169fclose(login_fp);170free(princname);171return retval;172}173174/***********************************************************175k5login_lookup looks for princname in file fp. Spaces176before the princaname (in the file ) are not ignored177spaces after the princname are ignored. If there are178any tokens after the principal name FALSE is returned.179180***********************************************************/181182krb5_error_code183k5login_lookup(FILE *fp, char *princname, krb5_boolean *found)184{185186krb5_error_code retval;187char * line;188char * fprinc;189char * lp;190krb5_boolean loc_found = FALSE;191192retval = get_line(fp, &line);193if (retval)194return retval;195196while (line){197fprinc = get_first_token (line, &lp);198199if (fprinc && (!strcmp(princname, fprinc))){200if( get_next_token (&lp) ){201free (line);202break; /* nothing should follow princname*/203}204else{205loc_found = TRUE;206free (line);207break;208}209}210211free (line);212213retval = get_line(fp, &line);214if (retval)215return retval;216}217218219*found = loc_found;220return 0;221222}223224/***********************************************************225k5users_lookup looks for princname in file fp. Spaces226before the princaname (in the file ) are not ignored227spaces after the princname are ignored.228229authorization alg:230231if princname is not found return false.232233if princname is found{234if cmd == NULL then the file entry after principal235name must be nothing or *236237if cmd !=NULL then entry must be matched (* is ok)238}239240241***********************************************************/242krb5_error_code243k5users_lookup(FILE *fp, char *princname, char *cmd,244krb5_boolean *found, char **out_fcmd)245{246krb5_error_code retval;247char * line;248char * fprinc, *fcmd;249char * lp;250char * loc_fcmd = NULL;251krb5_boolean loc_found = FALSE;252253retval = get_line(fp, &line);254if (retval)255return retval;256257while (line){258fprinc = get_first_token (line, &lp);259260if (fprinc && (!strcmp(princname, fprinc))){261fcmd = get_next_token (&lp);262263if ((fcmd) && (!strcmp(fcmd, PERMIT_ALL_COMMANDS))){264if (get_next_token(&lp) == NULL){265loc_fcmd =cmd ? xstrdup(cmd): NULL;266loc_found = TRUE;267}268free (line);269break;270}271272if (cmd == NULL){273if (fcmd == NULL)274loc_found = TRUE;275free (line);276break;277278}else{279if (fcmd != NULL) {280char * temp_rfcmd, *err;281krb5_boolean match;282do {283if(match_commands(fcmd,cmd,&match,284&temp_rfcmd, &err)){285if (auth_debug){286fprintf(stderr,"%s",err);287}288loc_fcmd = err;289break;290}else{291if (match == TRUE){292loc_fcmd = temp_rfcmd;293loc_found = TRUE;294break;295}296}297298}while ((fcmd = get_next_token( &lp)));299}300free (line);301break;302}303}304305free (line);306307retval = get_line(fp, &line);308if (retval) {309return retval;310}311}312313*out_fcmd = loc_fcmd;314*found = loc_found;315return 0;316317}318319320/***********************************************321fcmd_resolve -322takes a command specified .k5users file and323resolves it into a full path name.324325************************************************/326327krb5_boolean328fcmd_resolve(char *fcmd, char ***out_fcmd, char **out_err)329{330char * err;331char ** tmp_fcmd = NULL;332char * path_ptr, *path;333char * lp, * tc;334int i=0;335krb5_boolean ok = FALSE;336337tmp_fcmd = (char **) xcalloc (MAX_CMD, sizeof(char *));338339if (*fcmd == '/'){ /* must be full path */340tmp_fcmd[0] = xstrdup(fcmd);341tmp_fcmd[1] = NULL;342*out_fcmd = tmp_fcmd;343tmp_fcmd = NULL;344}else{345/* must be either full path or just the cmd name */346if (strchr(fcmd, '/')){347asprintf(&err, _("Error: bad entry - %s in %s file, must be "348"either full path or just the cmd name\n"),349fcmd, KRB5_USERS_NAME);350*out_err = err;351goto cleanup;352}353354#ifndef CMD_PATH355asprintf(&err, _("Error: bad entry - %s in %s file, since %s is just "356"the cmd name, CMD_PATH must be defined \n"),357fcmd, KRB5_USERS_NAME, fcmd);358*out_err = err;359goto cleanup;360#else361362path = xstrdup (CMD_PATH);363path_ptr = path;364365while ((*path_ptr == ' ') || (*path_ptr == '\t')) path_ptr ++;366367tc = get_first_token (path_ptr, &lp);368369if (! tc){370asprintf(&err, _("Error: bad entry - %s in %s file, CMD_PATH "371"contains no paths \n"), fcmd, KRB5_USERS_NAME);372*out_err = err;373goto cleanup;374}375376i=0;377do{378if (*tc != '/'){ /* must be full path */379asprintf(&err, _("Error: bad path %s in CMD_PATH for %s must "380"start with '/' \n"), tc, KRB5_USERS_NAME );381*out_err = err;382goto cleanup;383}384385tmp_fcmd[i] = xasprintf("%s/%s", tc, fcmd);386387i++;388389} while((tc = get_next_token (&lp)));390391tmp_fcmd[i] = NULL;392*out_fcmd = tmp_fcmd;393tmp_fcmd = NULL;394#endif /* CMD_PATH */395}396397ok = TRUE;398399cleanup:400free_fcmd_list(tmp_fcmd);401return ok;402}403404/********************************************405cmd_single - checks if cmd consists of a path406or a single token407408********************************************/409410krb5_boolean411cmd_single(char *cmd)412{413414if ( ( strrchr( cmd, '/')) == NULL){415return TRUE;416}else{417return FALSE;418}419}420421/********************************************422cmd_arr_cmp_postfix - compares a command with the postfix423of fcmd424********************************************/425426int427cmd_arr_cmp_postfix(char **fcmd_arr, char *cmd)428{429char * temp_fcmd;430char *ptr;431int result =1;432int i = 0;433434while(fcmd_arr[i]){435if ( (ptr = strrchr( fcmd_arr[i], '/')) == NULL){436temp_fcmd = fcmd_arr[i];437}else {438temp_fcmd = ptr + 1;439}440441result = strcmp (temp_fcmd, cmd);442if (result == 0){443break;444}445i++;446}447448return result;449450451}452453/**********************************************454cmd_arr_cmp - checks if cmd matches any455of the fcmd entries.456457**********************************************/458459int460cmd_arr_cmp(char **fcmd_arr, char *cmd)461{462int result =1;463int i = 0;464465while(fcmd_arr[i]){466result = strcmp (fcmd_arr[i], cmd);467if (result == 0){468break;469}470i++;471}472return result;473}474475476krb5_boolean477find_first_cmd_that_exists(char **fcmd_arr, char **cmd_out, char **err_out)478{479struct stat st_temp;480int i = 0;481krb5_boolean retbool= FALSE;482int j =0;483struct k5buf buf;484485while(fcmd_arr[i]){486if (!stat (fcmd_arr[i], &st_temp )){487*cmd_out = xstrdup(fcmd_arr[i]);488retbool = TRUE;489break;490}491i++;492}493494if (retbool == FALSE ){495k5_buf_init_dynamic(&buf);496k5_buf_add(&buf, _("Error: not found -> "));497for(j= 0; j < i; j ++)498k5_buf_add_fmt(&buf, " %s ", fcmd_arr[j]);499k5_buf_add(&buf, "\n");500*err_out = k5_buf_cstring(&buf);501if (*err_out == NULL) {502perror(prog_name);503exit(1);504}505}506507508return retbool;509}510511/***************************************************************512returns 1 if there is an error, 0 if no error.513514***************************************************************/515516int517match_commands(char *fcmd, char *cmd, krb5_boolean *match,518char **cmd_out, char **err_out)519{520char ** fcmd_arr = NULL;521char * err;522char * cmd_temp;523int result = 1;524525if(fcmd_resolve(fcmd, &fcmd_arr, &err )== FALSE ){526*err_out = err;527goto cleanup;528}529530if (cmd_single( cmd ) == TRUE){531if (!cmd_arr_cmp_postfix(fcmd_arr, cmd)){ /* found */532if (!find_first_cmd_that_exists(fcmd_arr, &cmd_temp, &err)) {533*err_out = err;534goto cleanup;535}536537*match = TRUE;538*cmd_out = cmd_temp;539} else {540*match = FALSE;541}542}else{543if (!cmd_arr_cmp(fcmd_arr, cmd)){ /* found */544*match = TRUE;545*cmd_out = xstrdup(cmd);546} else{547*match = FALSE;548}549}550551result = 0;552553cleanup:554free_fcmd_list(fcmd_arr);555return result;556}557558/*********************************************************559get_line - returns a line of any length. out_line560is set to null if eof.561*********************************************************/562563krb5_error_code564get_line(FILE *fp, char **out_line)565{566char * line, *r, *newline , *line_ptr;567int chunk_count = 1;568569line = (char *) xcalloc (BUFSIZ, sizeof (char ));570line_ptr = line;571line[0] = '\0';572573while (( r = fgets(line_ptr, BUFSIZ , fp)) != NULL){574newline = strchr(line_ptr, '\n');575if (newline) {576*newline = '\0';577break;578}579else {580chunk_count ++;581line = xrealloc(line, chunk_count * BUFSIZ);582583line_ptr = line + (BUFSIZ -1) *( chunk_count -1) ;584}585}586587if ((r == NULL) && (strlen(line) == 0)) {588*out_line = NULL;589}590else{591*out_line = line;592}593594return 0;595}596597/*******************************************************598get_first_token -599Expects a '\0' terminated input line .600If there are any spaces before the first token, they601will be returned as part of the first token.602603Note: this routine reuses the space pointed to by line604******************************************************/605606char *607get_first_token(char *line, char **lnext)608{609610char * lptr, * out_ptr;611612613out_ptr = line;614lptr = line;615616while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;617618if (strlen(lptr) == 0) return NULL;619620while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;621622if (*lptr == '\0'){623*lnext = lptr;624} else{625*lptr = '\0';626*lnext = lptr + 1;627}628629return out_ptr;630}631/**********************************************************632get_next_token -633returns the next token pointed to by *lnext.634returns NULL if there is no more tokens.635Note: that this function modifies the stream636pointed to by *lnext and does not allocate637space for the returned tocken. It also advances638lnext to the next tocken.639**********************************************************/640641char *642get_next_token (char **lnext)643{644char * lptr, * out_ptr;645646647lptr = *lnext;648649while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;650651if (strlen(lptr) == 0) return NULL;652653out_ptr = lptr;654655while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;656657if (*lptr == '\0'){658*lnext = lptr;659} else{660*lptr = '\0';661*lnext = lptr + 1;662}663664return out_ptr;665}666667void668init_auth_names(char *pw_dir)669{670const char *sep;671int r1, r2;672673sep = ((strlen(pw_dir) == 1) && (*pw_dir == '/')) ? "" : "/";674r1 = snprintf(k5login_path, sizeof(k5login_path), "%s%s%s",675pw_dir, sep, KRB5_LOGIN_NAME);676r2 = snprintf(k5users_path, sizeof(k5users_path), "%s%s%s",677pw_dir, sep, KRB5_USERS_NAME);678if (SNPRINTF_OVERFLOW(r1, sizeof(k5login_path)) ||679SNPRINTF_OVERFLOW(r2, sizeof(k5users_path))) {680fprintf(stderr, _("home directory name `%s' too long, can't search "681"for .k5login\n"), pw_dir);682exit (1);683}684}685686687