1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright (c) 1994 by the University of Southern California
5 * EXPORT OF THIS SOFTWARE from the United States of America may
6 * require a specific license from the United States Government.
7 * It is the responsibility of any person or organization contemplating
8 * export to obtain such a license before exporting.
10 * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
11 * this software and its documentation in source and binary forms is
12 * hereby granted, provided that any documentation or other materials
13 * related to such distribution or use acknowledge that the software
14 * was developed by the University of Southern California.
16 * DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The
17 * University of Southern California MAKES NO REPRESENTATIONS OR
18 * WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not
19 * limitation, the University of Southern California MAKES NO
20 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
21 * PARTICULAR PURPOSE. The University of Southern
22 * California shall not be held liable for any liability nor for any
23 * direct, indirect, or consequential damages with respect to any
24 * claim by the user or distributor of the ksu software.
26 * KSU was writen by: Ari Medvinsky, ari@isi.edu
31 static void auth_cleanup (FILE *, FILE *, char *);
33 krb5_boolean fowner(fp, uid)
40 * For security reasons, file must be owned either by
41 * the user himself, or by root. Otherwise, don't grant access.
43 if (fstat(fileno(fp), &sbuf)) {
47 if ((sbuf.st_uid != uid) && sbuf.st_uid) {
55 * Given a Kerberos principal "principal", and a local username "luser",
56 * determine whether user is authorized to login according to the
57 * authorization files ~luser/.k5login" and ~luser/.k5users. Returns TRUE
58 * if authorized, FALSE if not authorized.
62 krb5_error_code krb5_authorization(context, principal, luser,
66 krb5_principal principal;
77 krb5_boolean retbool =FALSE;
78 FILE * login_fp = 0, * users_fp = 0;
79 krb5_error_code retval = 0;
84 /* no account => no access */
85 if ((pwd = getpwnam(luser)) == NULL)
88 retval = krb5_unparse_name(context, principal, &princname);
93 printf("principal to be authorized %s\n", princname);
94 printf("login file: %s\n", k5login_path);
95 printf("users file: %s\n", k5users_path);
98 k5login_flag = stat(k5login_path, &st_temp);
99 k5users_flag = stat(k5users_path, &st_temp);
101 /* k5login and k5users must be owned by target user or root */
103 if ((login_fp = fopen(k5login_path, "r")) == NULL)
105 if ( fowner(login_fp, pwd->pw_uid) == FALSE) {
112 if ((users_fp = fopen(k5users_path, "r")) == NULL) {
115 if ( fowner(users_fp, pwd->pw_uid) == FALSE){
123 "In krb5_authorization: if auth files exist -> can access\n");
129 return 0; /* if kusers does not exist -> done */
131 if(retval = k5users_lookup(users_fp,princname,
132 cmd,&retbool,out_fcmd)){
133 auth_cleanup(users_fp, login_fp, princname);
143 /* if either file exists,
144 first see if the principal is in the login in file,
145 if it's not there check the k5users file */
150 "In krb5_authorization: principal to be authorized %s\n",
153 retval = k5login_lookup(login_fp, princname, &retbool);
155 auth_cleanup(users_fp, login_fp, princname);
160 *out_fcmd = xstrdup(cmd);
164 if ((!k5users_flag) && (retbool == FALSE) ){
165 retval = k5users_lookup (users_fp, princname,
166 cmd, &retbool, out_fcmd);
168 auth_cleanup(users_fp, login_fp, princname);
173 if (k5login_flag && k5users_flag){
175 char * kuser = (char *) xcalloc (strlen(princname), sizeof(char));
176 if (!(krb5_aname_to_localname(context, principal,
177 strlen(princname), kuser))
178 && (strcmp(kuser, luser) == 0)) {
186 auth_cleanup(users_fp, login_fp, princname);
190 /***********************************************************
191 k5login_lookup looks for princname in file fp. Spaces
192 before the princaname (in the file ) are not ignored
193 spaces after the princname are ignored. If there are
194 any tokens after the principal name FALSE is returned.
196 ***********************************************************/
198 krb5_error_code k5login_lookup (fp, princname, found)
204 krb5_error_code retval;
208 krb5_boolean loc_found = FALSE;
210 retval = get_line(fp, &line);
215 fprinc = get_first_token (line, &lp);
217 if (fprinc && (!strcmp(princname, fprinc))){
218 if( get_next_token (&lp) ){
220 break; /* nothing should follow princname*/
231 retval = get_line(fp, &line);
242 /***********************************************************
243 k5users_lookup looks for princname in file fp. Spaces
244 before the princaname (in the file ) are not ignored
245 spaces after the princname are ignored.
249 if princname is not found return false.
251 if princname is found{
252 if cmd == NULL then the file entry after principal
253 name must be nothing or *
255 if cmd !=NULL then entry must be matched (* is ok)
259 ***********************************************************/
260 krb5_error_code k5users_lookup (fp, princname, cmd, found, out_fcmd)
267 krb5_error_code retval;
269 char * fprinc, *fcmd;
271 char * loc_fcmd = NULL;
272 krb5_boolean loc_found = FALSE;
274 retval = get_line(fp, &line);
279 fprinc = get_first_token (line, &lp);
281 if (fprinc && (!strcmp(princname, fprinc))){
282 fcmd = get_next_token (&lp);
284 if ((fcmd) && (!strcmp(fcmd, PERMIT_ALL_COMMANDS))){
285 if (get_next_token(&lp) == NULL){
286 loc_fcmd =cmd ? xstrdup(cmd): NULL;
301 char * temp_rfcmd, *err;
304 if(match_commands(fcmd,cmd,&match,
307 fprintf(stderr,"%s",err);
313 loc_fcmd = temp_rfcmd;
319 }while ((fcmd = get_next_token( &lp)));
328 retval = get_line(fp, &line);
334 *out_fcmd = loc_fcmd;
341 /***********************************************
343 takes a command specified .k5users file and
344 resolves it into a full path name.
346 ************************************************/
348 krb5_boolean fcmd_resolve(fcmd, out_fcmd, out_err)
355 char * path_ptr, *path;
359 tmp_fcmd = (char **) xcalloc (MAX_CMD, sizeof(char *));
361 if (*fcmd == '/'){ /* must be full path */
362 tmp_fcmd[0] = xstrdup(fcmd);
364 *out_fcmd = tmp_fcmd;
367 /* must be either full path or just the cmd name */
368 if (strchr(fcmd, '/')){
369 asprintf(&err, _("Error: bad entry - %s in %s file, must be "
370 "either full path or just the cmd name\n"),
371 fcmd, KRB5_USERS_NAME);
377 asprintf(&err, _("Error: bad entry - %s in %s file, since %s is just "
378 "the cmd name, CMD_PATH must be defined \n"),
379 fcmd, KRB5_USERS_NAME, fcmd);
384 path = xstrdup (CMD_PATH);
387 while ((*path_ptr == ' ') || (*path_ptr == '\t')) path_ptr ++;
389 tc = get_first_token (path_ptr, &lp);
392 asprintf(&err, _("Error: bad entry - %s in %s file, CMD_PATH "
393 "contains no paths \n"), fcmd, KRB5_USERS_NAME);
400 if (*tc != '/'){ /* must be full path */
401 asprintf(&err, _("Error: bad path %s in CMD_PATH for %s must "
402 "start with '/' \n"), tc, KRB5_USERS_NAME );
407 tmp_fcmd[i] = xasprintf("%s/%s", tc, fcmd);
411 } while((tc = get_next_token (&lp)));
414 *out_fcmd = tmp_fcmd;
417 #endif /* CMD_PATH */
421 /********************************************
422 cmd_single - checks if cmd consists of a path
425 ********************************************/
427 krb5_boolean cmd_single(cmd)
431 if ( ( strrchr( cmd, '/')) == NULL){
438 /********************************************
439 cmd_arr_cmp_postfix - compares a command with the postfix
441 ********************************************/
443 int cmd_arr_cmp_postfix(fcmd_arr, cmd)
453 if ( (ptr = strrchr( fcmd_arr[i], '/')) == NULL){
454 temp_fcmd = fcmd_arr[i];
459 result = strcmp (temp_fcmd, cmd);
471 /**********************************************
472 cmd_arr_cmp - checks if cmd matches any
475 **********************************************/
477 int cmd_arr_cmp (fcmd_arr, cmd)
485 result = strcmp (fcmd_arr[i], cmd);
495 krb5_boolean find_first_cmd_that_exists(fcmd_arr, cmd_out, err_out)
502 krb5_boolean retbool= FALSE;
507 if (!stat (fcmd_arr[i], &st_temp )){
508 *cmd_out = xstrdup(fcmd_arr[i]);
515 if (retbool == FALSE ){
516 k5_buf_init_dynamic(&buf);
517 k5_buf_add(&buf, _("Error: not found -> "));
518 for(j= 0; j < i; j ++)
519 k5_buf_add_fmt(&buf, " %s ", fcmd_arr[j]);
520 k5_buf_add(&buf, "\n");
521 if (k5_buf_status(&buf) != 0) {
532 /***************************************************************
533 returns 1 if there is an error, 0 if no error.
535 ***************************************************************/
537 int match_commands (fcmd, cmd, match, cmd_out, err_out)
548 if(fcmd_resolve(fcmd, &fcmd_arr, &err )== FALSE ){
553 if (cmd_single( cmd ) == TRUE){
554 if (!cmd_arr_cmp_postfix(fcmd_arr, cmd)){ /* found */
556 if(find_first_cmd_that_exists( fcmd_arr,&cmd_temp,&err)== TRUE){
569 if (!cmd_arr_cmp(fcmd_arr, cmd)){ /* found */
571 *cmd_out = xstrdup(cmd);
581 /*********************************************************
582 get_line - returns a line of any length. out_line
583 is set to null if eof.
584 *********************************************************/
586 krb5_error_code get_line (fp, out_line)
592 char * line, *r, *newline , *line_ptr;
595 line = (char *) xcalloc (BUFSIZ, sizeof (char ));
599 while (( r = fgets(line_ptr, BUFSIZ , fp)) != NULL){
600 newline = strchr(line_ptr, '\n');
607 if(!( line = (char *) realloc( line,
608 chunk_count * sizeof(char) * BUFSIZ))){
612 line_ptr = line + (BUFSIZ -1) *( chunk_count -1) ;
616 if ((r == NULL) && (strlen(line) == 0)) {
626 /*******************************************************
628 Expects a '\0' terminated input line .
629 If there are any spaces before the first token, they
630 will be returned as part of the first token.
632 Note: this routine reuses the space pointed to by line
633 ******************************************************/
635 char * get_first_token (line, lnext)
640 char * lptr, * out_ptr;
646 while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;
648 if (strlen(lptr) == 0) return NULL;
650 while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;
661 /**********************************************************
663 returns the next token pointed to by *lnext.
664 returns NULL if there is no more tokens.
665 Note: that this function modifies the stream
666 pointed to by *lnext and does not allocate
667 space for the returned tocken. It also advances
668 lnext to the next tocken.
669 **********************************************************/
671 char * get_next_token (lnext)
674 char * lptr, * out_ptr;
679 while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;
681 if (strlen(lptr) == 0) return NULL;
685 while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;
697 static void auth_cleanup(users_fp, login_fp, princname)
710 void init_auth_names(pw_dir)
716 sep = ((strlen(pw_dir) == 1) && (*pw_dir == '/')) ? "" : "/";
717 r1 = snprintf(k5login_path, sizeof(k5login_path), "%s%s%s",
718 pw_dir, sep, KRB5_LOGIN_NAME);
719 r2 = snprintf(k5users_path, sizeof(k5users_path), "%s%s%s",
720 pw_dir, sep, KRB5_USERS_NAME);
721 if (SNPRINTF_OVERFLOW(r1, sizeof(k5login_path)) ||
722 SNPRINTF_OVERFLOW(r2, sizeof(k5users_path))) {
723 fprintf(stderr, _("home directory name `%s' too long, can't search "
724 "for .k5login\n"), pw_dir);