aboutsummaryrefslogtreecommitdiff
path: root/src/clients/ksu/authorization.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/clients/ksu/authorization.c')
-rw-r--r--src/clients/ksu/authorization.c727
1 files changed, 727 insertions, 0 deletions
diff --git a/src/clients/ksu/authorization.c b/src/clients/ksu/authorization.c
new file mode 100644
index 000000000000..90aafbd7595b
--- /dev/null
+++ b/src/clients/ksu/authorization.c
@@ -0,0 +1,727 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (c) 1994 by the University of Southern California
+ *
+ * EXPORT OF THIS SOFTWARE from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
+ * this software and its documentation in source and binary forms is
+ * hereby granted, provided that any documentation or other materials
+ * related to such distribution or use acknowledge that the software
+ * was developed by the University of Southern California.
+ *
+ * DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The
+ * University of Southern California MAKES NO REPRESENTATIONS OR
+ * WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not
+ * limitation, the University of Southern California MAKES NO
+ * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
+ * PARTICULAR PURPOSE. The University of Southern
+ * California shall not be held liable for any liability nor for any
+ * direct, indirect, or consequential damages with respect to any
+ * claim by the user or distributor of the ksu software.
+ *
+ * KSU was writen by: Ari Medvinsky, ari@isi.edu
+ */
+
+#include "ksu.h"
+
+static void auth_cleanup (FILE *, FILE *, char *);
+
+krb5_boolean fowner(fp, uid)
+ FILE *fp;
+ uid_t uid;
+{
+ struct stat sbuf;
+
+ /*
+ * For security reasons, file must be owned either by
+ * the user himself, or by root. Otherwise, don't grant access.
+ */
+ if (fstat(fileno(fp), &sbuf)) {
+ return(FALSE);
+ }
+
+ if ((sbuf.st_uid != uid) && sbuf.st_uid) {
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/*
+ * Given a Kerberos principal "principal", and a local username "luser",
+ * determine whether user is authorized to login according to the
+ * authorization files ~luser/.k5login" and ~luser/.k5users. Returns TRUE
+ * if authorized, FALSE if not authorized.
+ *
+ */
+
+krb5_error_code krb5_authorization(context, principal, luser,
+ cmd, ok, out_fcmd)
+/* IN */
+ krb5_context context;
+ krb5_principal principal;
+ const char *luser;
+ char *cmd;
+ /* OUT */
+ krb5_boolean *ok;
+ char **out_fcmd;
+{
+ struct passwd *pwd;
+ char *princname;
+ int k5login_flag =0;
+ int k5users_flag =0;
+ krb5_boolean retbool =FALSE;
+ FILE * login_fp = 0, * users_fp = 0;
+ krb5_error_code retval = 0;
+ struct stat st_temp;
+
+ *ok =FALSE;
+
+ /* no account => no access */
+ if ((pwd = getpwnam(luser)) == NULL)
+ return 0;
+
+ retval = krb5_unparse_name(context, principal, &princname);
+ if (retval)
+ return retval;
+
+#ifdef DEBUG
+ printf("principal to be authorized %s\n", princname);
+ printf("login file: %s\n", k5login_path);
+ printf("users file: %s\n", k5users_path);
+#endif
+
+ k5login_flag = stat(k5login_path, &st_temp);
+ k5users_flag = stat(k5users_path, &st_temp);
+
+ /* k5login and k5users must be owned by target user or root */
+ if (!k5login_flag){
+ if ((login_fp = fopen(k5login_path, "r")) == NULL)
+ return 0;
+ if ( fowner(login_fp, pwd->pw_uid) == FALSE) {
+ fclose(login_fp);
+ return 0;
+ }
+ }
+
+ if (!k5users_flag){
+ if ((users_fp = fopen(k5users_path, "r")) == NULL) {
+ return 0;
+ }
+ if ( fowner(users_fp, pwd->pw_uid) == FALSE){
+ fclose(users_fp);
+ return 0;
+ }
+ }
+
+ if (auth_debug){
+ fprintf(stderr,
+ "In krb5_authorization: if auth files exist -> can access\n");
+ }
+
+#if 0
+ if (cmd){
+ if(k5users_flag){
+ return 0; /* if kusers does not exist -> done */
+ }else{
+ if(retval = k5users_lookup(users_fp,princname,
+ cmd,&retbool,out_fcmd)){
+ auth_cleanup(users_fp, login_fp, princname);
+ return retval;
+ }else{
+ *ok =retbool;
+ return retval;
+ }
+ }
+ }
+#endif
+
+ /* if either file exists,
+ first see if the principal is in the login in file,
+ if it's not there check the k5users file */
+
+ if (!k5login_flag){
+ if (auth_debug)
+ fprintf(stderr,
+ "In krb5_authorization: principal to be authorized %s\n",
+ princname);
+
+ retval = k5login_lookup(login_fp, princname, &retbool);
+ if (retval) {
+ auth_cleanup(users_fp, login_fp, princname);
+ return retval;
+ }
+ if (retbool) {
+ if (cmd)
+ *out_fcmd = xstrdup(cmd);
+ }
+ }
+
+ if ((!k5users_flag) && (retbool == FALSE) ){
+ retval = k5users_lookup (users_fp, princname,
+ cmd, &retbool, out_fcmd);
+ if(retval) {
+ auth_cleanup(users_fp, login_fp, princname);
+ return retval;
+ }
+ }
+
+ if (k5login_flag && k5users_flag){
+
+ char * kuser = (char *) xcalloc (strlen(princname), sizeof(char));
+ if (!(krb5_aname_to_localname(context, principal,
+ strlen(princname), kuser))
+ && (strcmp(kuser, luser) == 0)) {
+ retbool = TRUE;
+ }
+
+ free(kuser);
+ }
+
+ *ok =retbool;
+ auth_cleanup(users_fp, login_fp, princname);
+ return 0;
+}
+
+/***********************************************************
+k5login_lookup looks for princname in file fp. Spaces
+before the princaname (in the file ) are not ignored
+spaces after the princname are ignored. If there are
+any tokens after the principal name FALSE is returned.
+
+***********************************************************/
+
+krb5_error_code k5login_lookup (fp, princname, found)
+ FILE *fp;
+ char *princname;
+ krb5_boolean *found;
+{
+
+ krb5_error_code retval;
+ char * line;
+ char * fprinc;
+ char * lp;
+ krb5_boolean loc_found = FALSE;
+
+ retval = get_line(fp, &line);
+ if (retval)
+ return retval;
+
+ while (line){
+ fprinc = get_first_token (line, &lp);
+
+ if (fprinc && (!strcmp(princname, fprinc))){
+ if( get_next_token (&lp) ){
+ free (line);
+ break; /* nothing should follow princname*/
+ }
+ else{
+ loc_found = TRUE;
+ free (line);
+ break;
+ }
+ }
+
+ free (line);
+
+ retval = get_line(fp, &line);
+ if (retval)
+ return retval;
+ }
+
+
+ *found = loc_found;
+ return 0;
+
+}
+
+/***********************************************************
+k5users_lookup looks for princname in file fp. Spaces
+before the princaname (in the file ) are not ignored
+spaces after the princname are ignored.
+
+authorization alg:
+
+if princname is not found return false.
+
+if princname is found{
+ if cmd == NULL then the file entry after principal
+ name must be nothing or *
+
+ if cmd !=NULL then entry must be matched (* is ok)
+}
+
+
+***********************************************************/
+krb5_error_code k5users_lookup (fp, princname, cmd, found, out_fcmd)
+ FILE *fp;
+ char *princname;
+ char *cmd;
+ krb5_boolean *found;
+ char **out_fcmd;
+{
+ krb5_error_code retval;
+ char * line;
+ char * fprinc, *fcmd;
+ char * lp;
+ char * loc_fcmd = NULL;
+ krb5_boolean loc_found = FALSE;
+
+ retval = get_line(fp, &line);
+ if (retval)
+ return retval;
+
+ while (line){
+ fprinc = get_first_token (line, &lp);
+
+ if (fprinc && (!strcmp(princname, fprinc))){
+ fcmd = get_next_token (&lp);
+
+ if ((fcmd) && (!strcmp(fcmd, PERMIT_ALL_COMMANDS))){
+ if (get_next_token(&lp) == NULL){
+ loc_fcmd =cmd ? xstrdup(cmd): NULL;
+ loc_found = TRUE;
+ }
+ free (line);
+ break;
+ }
+
+ if (cmd == NULL){
+ if (fcmd == NULL)
+ loc_found = TRUE;
+ free (line);
+ break;
+
+ }else{
+ if (fcmd != NULL) {
+ char * temp_rfcmd, *err;
+ krb5_boolean match;
+ do {
+ if(match_commands(fcmd,cmd,&match,
+ &temp_rfcmd, &err)){
+ if (auth_debug){
+ fprintf(stderr,"%s",err);
+ }
+ loc_fcmd = err;
+ break;
+ }else{
+ if (match == TRUE){
+ loc_fcmd = temp_rfcmd;
+ loc_found = TRUE;
+ break;
+ }
+ }
+
+ }while ((fcmd = get_next_token( &lp)));
+ }
+ free (line);
+ break;
+ }
+ }
+
+ free (line);
+
+ retval = get_line(fp, &line);
+ if (retval) {
+ return retval;
+ }
+ }
+
+ *out_fcmd = loc_fcmd;
+ *found = loc_found;
+ return 0;
+
+}
+
+
+/***********************************************
+fcmd_resolve -
+takes a command specified .k5users file and
+resolves it into a full path name.
+
+************************************************/
+
+krb5_boolean fcmd_resolve(fcmd, out_fcmd, out_err)
+ char *fcmd;
+ char ***out_fcmd;
+ char **out_err;
+{
+ char * err;
+ char ** tmp_fcmd;
+ char * path_ptr, *path;
+ char * lp, * tc;
+ int i=0;
+
+ tmp_fcmd = (char **) xcalloc (MAX_CMD, sizeof(char *));
+
+ if (*fcmd == '/'){ /* must be full path */
+ tmp_fcmd[0] = xstrdup(fcmd);
+ tmp_fcmd[1] = NULL;
+ *out_fcmd = tmp_fcmd;
+ return TRUE;
+ }else{
+ /* must be either full path or just the cmd name */
+ if (strchr(fcmd, '/')){
+ asprintf(&err, _("Error: bad entry - %s in %s file, must be "
+ "either full path or just the cmd name\n"),
+ fcmd, KRB5_USERS_NAME);
+ *out_err = err;
+ return FALSE;
+ }
+
+#ifndef CMD_PATH
+ asprintf(&err, _("Error: bad entry - %s in %s file, since %s is just "
+ "the cmd name, CMD_PATH must be defined \n"),
+ fcmd, KRB5_USERS_NAME, fcmd);
+ *out_err = err;
+ return FALSE;
+#else
+
+ path = xstrdup (CMD_PATH);
+ path_ptr = path;
+
+ while ((*path_ptr == ' ') || (*path_ptr == '\t')) path_ptr ++;
+
+ tc = get_first_token (path_ptr, &lp);
+
+ if (! tc){
+ asprintf(&err, _("Error: bad entry - %s in %s file, CMD_PATH "
+ "contains no paths \n"), fcmd, KRB5_USERS_NAME);
+ *out_err = err;
+ return FALSE;
+ }
+
+ i=0;
+ do{
+ if (*tc != '/'){ /* must be full path */
+ asprintf(&err, _("Error: bad path %s in CMD_PATH for %s must "
+ "start with '/' \n"), tc, KRB5_USERS_NAME );
+ *out_err = err;
+ return FALSE;
+ }
+
+ tmp_fcmd[i] = xasprintf("%s/%s", tc, fcmd);
+
+ i++;
+
+ } while((tc = get_next_token (&lp)));
+
+ tmp_fcmd[i] = NULL;
+ *out_fcmd = tmp_fcmd;
+ return TRUE;
+
+#endif /* CMD_PATH */
+ }
+}
+
+/********************************************
+cmd_single - checks if cmd consists of a path
+ or a single token
+
+********************************************/
+
+krb5_boolean cmd_single(cmd)
+ char * cmd;
+{
+
+ if ( ( strrchr( cmd, '/')) == NULL){
+ return TRUE;
+ }else{
+ return FALSE;
+ }
+}
+
+/********************************************
+cmd_arr_cmp_postfix - compares a command with the postfix
+ of fcmd
+********************************************/
+
+int cmd_arr_cmp_postfix(fcmd_arr, cmd)
+ char **fcmd_arr;
+ char *cmd;
+{
+ char * temp_fcmd;
+ char *ptr;
+ int result =1;
+ int i = 0;
+
+ while(fcmd_arr[i]){
+ if ( (ptr = strrchr( fcmd_arr[i], '/')) == NULL){
+ temp_fcmd = fcmd_arr[i];
+ }else {
+ temp_fcmd = ptr + 1;
+ }
+
+ result = strcmp (temp_fcmd, cmd);
+ if (result == 0){
+ break;
+ }
+ i++;
+ }
+
+ return result;
+
+
+}
+
+/**********************************************
+cmd_arr_cmp - checks if cmd matches any
+ of the fcmd entries.
+
+**********************************************/
+
+int cmd_arr_cmp (fcmd_arr, cmd)
+ char **fcmd_arr;
+ char *cmd;
+{
+ int result =1;
+ int i = 0;
+
+ while(fcmd_arr[i]){
+ result = strcmp (fcmd_arr[i], cmd);
+ if (result == 0){
+ break;
+ }
+ i++;
+ }
+ return result;
+}
+
+
+krb5_boolean find_first_cmd_that_exists(fcmd_arr, cmd_out, err_out)
+ char **fcmd_arr;
+ char **cmd_out;
+ char **err_out;
+{
+ struct stat st_temp;
+ int i = 0;
+ krb5_boolean retbool= FALSE;
+ int j =0;
+ struct k5buf buf;
+
+ while(fcmd_arr[i]){
+ if (!stat (fcmd_arr[i], &st_temp )){
+ *cmd_out = xstrdup(fcmd_arr[i]);
+ retbool = TRUE;
+ break;
+ }
+ i++;
+ }
+
+ if (retbool == FALSE ){
+ k5_buf_init_dynamic(&buf);
+ k5_buf_add(&buf, _("Error: not found -> "));
+ for(j= 0; j < i; j ++)
+ k5_buf_add_fmt(&buf, " %s ", fcmd_arr[j]);
+ k5_buf_add(&buf, "\n");
+ if (k5_buf_status(&buf) != 0) {
+ perror(prog_name);
+ exit(1);
+ }
+ *err_out = buf.data;
+ }
+
+
+ return retbool;
+}
+
+/***************************************************************
+returns 1 if there is an error, 0 if no error.
+
+***************************************************************/
+
+int match_commands (fcmd, cmd, match, cmd_out, err_out)
+ char *fcmd;
+ char *cmd;
+ krb5_boolean *match;
+ char **cmd_out;
+ char **err_out;
+{
+ char ** fcmd_arr;
+ char * err;
+ char * cmd_temp;
+
+ if(fcmd_resolve(fcmd, &fcmd_arr, &err )== FALSE ){
+ *err_out = err;
+ return 1;
+ }
+
+ if (cmd_single( cmd ) == TRUE){
+ if (!cmd_arr_cmp_postfix(fcmd_arr, cmd)){ /* found */
+
+ if(find_first_cmd_that_exists( fcmd_arr,&cmd_temp,&err)== TRUE){
+ *match = TRUE;
+ *cmd_out = cmd_temp;
+ return 0;
+ }else{
+ *err_out = err;
+ return 1;
+ }
+ }else{
+ *match = FALSE;
+ return 0;
+ }
+ }else{
+ if (!cmd_arr_cmp(fcmd_arr, cmd)){ /* found */
+ *match = TRUE;
+ *cmd_out = xstrdup(cmd);
+ return 0;
+ } else{
+ *match = FALSE;
+ return 0;
+ }
+ }
+
+}
+
+/*********************************************************
+ get_line - returns a line of any length. out_line
+ is set to null if eof.
+*********************************************************/
+
+krb5_error_code get_line (fp, out_line)
+/* IN */
+ FILE *fp;
+ /* OUT */
+ char **out_line;
+{
+ char * line, *r, *newline , *line_ptr;
+ int chunk_count = 1;
+
+ line = (char *) xcalloc (BUFSIZ, sizeof (char ));
+ line_ptr = line;
+ line[0] = '\0';
+
+ while (( r = fgets(line_ptr, BUFSIZ , fp)) != NULL){
+ newline = strchr(line_ptr, '\n');
+ if (newline) {
+ *newline = '\0';
+ break;
+ }
+ else {
+ chunk_count ++;
+ if(!( line = (char *) realloc( line,
+ chunk_count * sizeof(char) * BUFSIZ))){
+ return ENOMEM;
+ }
+
+ line_ptr = line + (BUFSIZ -1) *( chunk_count -1) ;
+ }
+ }
+
+ if ((r == NULL) && (strlen(line) == 0)) {
+ *out_line = NULL;
+ }
+ else{
+ *out_line = line;
+ }
+
+ return 0;
+}
+
+/*******************************************************
+get_first_token -
+Expects a '\0' terminated input line .
+If there are any spaces before the first token, they
+will be returned as part of the first token.
+
+Note: this routine reuses the space pointed to by line
+******************************************************/
+
+char * get_first_token (line, lnext)
+ char *line;
+ char **lnext;
+{
+
+ char * lptr, * out_ptr;
+
+
+ out_ptr = line;
+ lptr = line;
+
+ while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;
+
+ if (strlen(lptr) == 0) return NULL;
+
+ while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;
+
+ if (*lptr == '\0'){
+ *lnext = lptr;
+ } else{
+ *lptr = '\0';
+ *lnext = lptr + 1;
+ }
+
+ return out_ptr;
+}
+/**********************************************************
+get_next_token -
+returns the next token pointed to by *lnext.
+returns NULL if there is no more tokens.
+Note: that this function modifies the stream
+ pointed to by *lnext and does not allocate
+ space for the returned tocken. It also advances
+ lnext to the next tocken.
+**********************************************************/
+
+char * get_next_token (lnext)
+ char **lnext;
+{
+ char * lptr, * out_ptr;
+
+
+ lptr = *lnext;
+
+ while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;
+
+ if (strlen(lptr) == 0) return NULL;
+
+ out_ptr = lptr;
+
+ while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;
+
+ if (*lptr == '\0'){
+ *lnext = lptr;
+ } else{
+ *lptr = '\0';
+ *lnext = lptr + 1;
+ }
+
+ return out_ptr;
+}
+
+static void auth_cleanup(users_fp, login_fp, princname)
+ FILE *users_fp;
+ FILE *login_fp;
+ char *princname;
+{
+
+ free (princname);
+ if (users_fp)
+ fclose(users_fp);
+ if (login_fp)
+ fclose(login_fp);
+}
+
+void init_auth_names(pw_dir)
+ char *pw_dir;
+{
+ const char *sep;
+ int r1, r2;
+
+ sep = ((strlen(pw_dir) == 1) && (*pw_dir == '/')) ? "" : "/";
+ r1 = snprintf(k5login_path, sizeof(k5login_path), "%s%s%s",
+ pw_dir, sep, KRB5_LOGIN_NAME);
+ r2 = snprintf(k5users_path, sizeof(k5users_path), "%s%s%s",
+ pw_dir, sep, KRB5_USERS_NAME);
+ if (SNPRINTF_OVERFLOW(r1, sizeof(k5login_path)) ||
+ SNPRINTF_OVERFLOW(r2, sizeof(k5users_path))) {
+ fprintf(stderr, _("home directory name `%s' too long, can't search "
+ "for .k5login\n"), pw_dir);
+ exit (1);
+ }
+}