?? parse.c
字號:
/* * sudo version 1.1 allows users to execute commands as root * Copyright (C) 1991 The Root Group, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 1, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * If you make modifications to the source, we would be happy to have * them to include in future releases. Feel free to send them to: * Jeff Nieusma nieusma@rootgroup.com * 3959 Arbol CT (303) 447-8093 * Boulder, CO 80301-1752 ********************************************************************************** parse.c, sudo project* David R. Hieb* March 18, 1991** routines to implement and maintain the parsing and list management.*******************************************************************************/#include <stdio.h>#include <strings.h>#include <ctype.h>#include "sudo.h"/* there are 3 main lists (User, Host_Alias, Cmnd_Alias) and 1 extra list */#define NUM_LISTS 3+1extern char *user, *host, *cmnd;extern FILE *yyin, *yyout;int user_list_found = FALSE;int list_num, new_list[NUM_LISTS];int parse_error = FALSE, found_user = FALSE;int next_type, num_host_alias = 0, num_cmnd_alias = 0;LINK tmp_ptr, reset_ptr, save_ptr, list_ptr[NUM_LISTS];/******************************************************************************** inserts a node into list 'list_num' and updates list_ptr[list_num]*******************************************************************************/void insert_member(list_num, token_type, op_type, data_string)int token_type, list_num;char op_type;char *data_string;{ tmp_ptr = (LINK)malloc(sizeof(LIST)); tmp_ptr->type = token_type; tmp_ptr->op = op_type; tmp_ptr->data = (char *)malloc(strlen(data_string)+1); strcpy(tmp_ptr->data, data_string); tmp_ptr->next = (new_list[list_num] == TRUE) ? NULL : list_ptr[list_num]; list_ptr[list_num] = list_ptr[EXTRA_LIST] = tmp_ptr;}/******************************************************************************** diagnostic list printing utility that prints list 'list_num'*******************************************************************************/void print_list(list_num)int list_num;{LINK tmptmp_ptr;tmptmp_ptr = list_ptr[list_num];while (list_ptr[list_num] != NULL) { printf("type = %d, op = %c, data = %s\n", list_ptr[list_num]->type, list_ptr[list_num]->op, list_ptr[list_num]->data); tmp_ptr = list_ptr[list_num]; list_ptr[list_num] = tmp_ptr->next; }list_ptr[list_num] = tmptmp_ptr;}/******************************************************************************** delete list utility that deletes list 'list_num'*******************************************************************************/void delete_list(list_num)int list_num;{while (list_ptr[list_num] != NULL) { tmp_ptr = list_ptr[list_num]; list_ptr[list_num] = tmp_ptr->next;/* free(tmp_ptr); */ }}/******************************************************************************** this routine is what the lex/yacc code calls to build the different lists.* once the lists are all built, control eventually returns to validate().*******************************************************************************/int call_back(token_type, op_type, data_string)int token_type;char op_type;char *data_string;{/* all nodes start out in the extra list since the node name is received last */list_num = EXTRA_LIST;/* * if the last received node is TYPE1, then we can classify the list * and effectively transfer the extra list to the correct list type. */if (token_type == TYPE1) { /* we have just build a "Host_Alias" list */ if (strcmp(data_string, "Host_Alias") == 0) { list_num = HOST_LIST; if (num_host_alias > 0) { reset_ptr->next = list_ptr[HOST_LIST]; } num_host_alias++; } /* we have just build a "Cmnd_Alias" list */ else if (strcmp(data_string, "Cmnd_Alias") == 0) { list_num = CMND_LIST; if (num_cmnd_alias > 0) { reset_ptr->next = list_ptr[CMND_LIST]; } num_cmnd_alias++; } /* we have just build a "User" list */ else { list_num = USER_LIST; user_list_found = TRUE; } new_list[EXTRA_LIST] = TRUE; new_list[list_num] = FALSE; list_ptr[list_num] = list_ptr[EXTRA_LIST]; }/* actually link the new node into list 'list_num' */insert_member(list_num, token_type, op_type, data_string);if (new_list[list_num] == TRUE) { reset_ptr = list_ptr[list_num]; new_list[list_num] = FALSE; }/* * we process one user record at a time from the sudoers file. if we * find the user were looking for, we return to lex/yacc declaring * that we have done so. otherwise, we reset the user list, delete the * nodes and start over again looking for the user. */if (user_list_found == TRUE) { if (list_ptr[list_num]->type == TYPE1 && strcmp(list_ptr[list_num]->data, user) == 0) { return(FOUND_USER); } else { new_list[list_num] = TRUE; user_list_found = FALSE; delete_list(list_num); } }return(NOT_FOUND_USER);}/******************************************************************************** this routine is called from cmnd_check() to resolve whether or not* a user is permitted to perform a to-yet-be-determined command for* a certain host name.*******************************************************************************/int host_type_ok(){/* check for the reserved keyword 'ALL'. if so, don't check the host name */if (strcmp(list_ptr[USER_LIST]->data, "ALL") == 0) { return(TRUE); }/* this case is the normal lowercase hostname */else if (isupper(list_ptr[USER_LIST]->data[0]) == FALSE) { return(strcmp(list_ptr[USER_LIST]->data, host) == 0); }/* by now we have a Host_Alias that will have to be expanded */else { save_ptr = list_ptr[HOST_LIST]; while (list_ptr[HOST_LIST] != NULL) { if ((list_ptr[HOST_LIST]->type == TYPE2) && (strcmp(list_ptr[HOST_LIST]->data, list_ptr[USER_LIST]->data) == 0)) { next_type = list_ptr[HOST_LIST]->next->type; tmp_ptr = list_ptr[HOST_LIST]; list_ptr[HOST_LIST] = tmp_ptr->next; while (next_type == TYPE3) { if (strcmp(list_ptr[HOST_LIST]->data, host) == 0) { list_ptr[HOST_LIST] = save_ptr; return(TRUE); } if (list_ptr[HOST_LIST]->next != NULL) { next_type = list_ptr[HOST_LIST]->next->type; tmp_ptr = list_ptr[HOST_LIST]; list_ptr[HOST_LIST] = tmp_ptr->next; } else { next_type = ~TYPE3; } } } else { tmp_ptr = list_ptr[HOST_LIST]; list_ptr[HOST_LIST] = tmp_ptr->next; } } list_ptr[HOST_LIST] = save_ptr; return(FALSE); }}/******************************************************************************** this routine is called from cmnd_check() to resolve whether or not* a user is permitted to perform a certain command on the already* established host.*******************************************************************************/int cmnd_type_ok(){/* check for the reserved keyword 'ALL'. */if (strcmp(list_ptr[USER_LIST]->data, "ALL") == 0) { /* if the command has an absolute path, let them do it */ if (cmnd[0] == '/') { return(MATCH); } /* if the command does not have an absolute path, forget it */ else { return(NO_MATCH); } }/* if the command has an absolute path, check it out */else if (list_ptr[USER_LIST]->data[0] == '/') { /* op | data | return value *--------------------------------- * ' ' | No Match | return(NO_MATCH) * '!' | No Match | return(NO_MATCH) * ' ' | A Match | return(MATCH) * '!' | A Match | return(QUIT_NOW) * * these special cases are important in subtracting from the * Universe of commands in something like: * user machine=ALL,!/bin/rm,!/etc/named ... */ if (strcmp(list_ptr[USER_LIST]->data, cmnd) == 0) { if (list_ptr[USER_LIST]->op == '!') { return(QUIT_NOW); } else { return(MATCH); } } else { return(NO_MATCH); } }/* by now we have a Cmnd_Alias that will have to be expanded */else { save_ptr = list_ptr[CMND_LIST]; while (list_ptr[CMND_LIST] != NULL) { if ((list_ptr[CMND_LIST]->type == TYPE2) && (strcmp(list_ptr[CMND_LIST]->data, list_ptr[USER_LIST]->data) == 0)) { next_type = list_ptr[CMND_LIST]->next->type; tmp_ptr = list_ptr[CMND_LIST]; list_ptr[CMND_LIST] = tmp_ptr->next; while (next_type == TYPE3) { if (strcmp(list_ptr[CMND_LIST]->data, cmnd) == 0) { if (list_ptr[USER_LIST]->op == '!') { list_ptr[CMND_LIST] = save_ptr; return(QUIT_NOW); } else { list_ptr[CMND_LIST] = save_ptr; return(MATCH); } } if (list_ptr[CMND_LIST]->next != NULL) { next_type = list_ptr[CMND_LIST]->next->type; tmp_ptr = list_ptr[CMND_LIST]; list_ptr[CMND_LIST] = tmp_ptr->next; } else { next_type = ~TYPE3; } } } else { tmp_ptr = list_ptr[CMND_LIST]; list_ptr[CMND_LIST] = tmp_ptr->next; } } list_ptr[CMND_LIST] = save_ptr; return(NO_MATCH); }}/******************************************************************************** this routine is called from validate() after the call_back() routine* has built all the possible lists. this routine steps thru the user list* calling on host_type_ok() and cmnd_type_ok() trying to resolve whether* or not the user will be able to execute the command on the host.*******************************************************************************/int cmnd_check(){int return_code;while (list_ptr[USER_LIST] != NULL) { if ((list_ptr[USER_LIST]->type == TYPE2) && host_type_ok()) { next_type = list_ptr[USER_LIST]->next->type; tmp_ptr = list_ptr[USER_LIST]; list_ptr[USER_LIST] = tmp_ptr->next; while (next_type == TYPE3) { return_code = cmnd_type_ok(); if (return_code == MATCH) { return(VALIDATE_OK); } else if (return_code == QUIT_NOW) { return(VALIDATE_NOT_OK); } if (list_ptr[USER_LIST]->next != NULL) { next_type = list_ptr[USER_LIST]->next->type; tmp_ptr = list_ptr[USER_LIST]; list_ptr[USER_LIST] = tmp_ptr->next; } else { next_type = ~TYPE3; } } } else { tmp_ptr = list_ptr[USER_LIST]; list_ptr[USER_LIST] = tmp_ptr->next; } }return(VALIDATE_NOT_OK);}/******************************************************************************** this routine is called from the sudo.c module and tries to validate* the user, host and command triplet.*******************************************************************************/int validate(){FILE *sudoers_fp;int i, return_code;if ((sudoers_fp = fopen(SUDOERS, "r")) == NULL ) { perror(SUDOERS); log_error( NO_SUDOERS_FILE ); exit(1); }yyin = sudoers_fp;yyout = stdout;for (i = 0; i < NUM_LISTS; i++) new_list[i] = TRUE;/* * yyparse() returns with one of 3 values: 0) yyparse() worked fine; * 1) yyparse() failed; FOUND_USER) the user was found and yyparse() * was returned from prematurely. */return_code = yyparse();/* don't need to keep this open... */(void) fclose (sudoers_fp);/* if a parsing error occurred, set return_code accordingly */if (parse_error == TRUE) { return_code = PARSE_ERROR; }/* if the user was not found, set the return_code accordingly */if (found_user == FALSE) { return_code = NOT_FOUND_USER; }/* handle the 3 cases individually &*/switch(return_code) { case FOUND_USER: return_code = cmnd_check(); delete_list(USER_LIST); delete_list(HOST_LIST); delete_list(CMND_LIST); return(return_code); break; case NOT_FOUND_USER: return(VALIDATE_NO_USER); break; case PARSE_ERROR: return(VALIDATE_ERROR); break; }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -