Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/clients/ksu/authorization.c
34907 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/*
3
* Copyright (c) 1994 by the University of Southern California
4
*
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.
9
*
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.
15
*
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.
25
*
26
* KSU was written by: Ari Medvinsky, [email protected]
27
*/
28
29
#include "ksu.h"
30
31
static void
32
free_fcmd_list(char **list)
33
{
34
size_t i;
35
36
if (list == NULL)
37
return;
38
for (i = 0; i < MAX_CMD && list[i] != NULL; i++)
39
free(list[i]);
40
free(list);
41
}
42
43
krb5_boolean
44
fowner(FILE *fp, uid_t uid)
45
{
46
struct stat sbuf;
47
48
/*
49
* For security reasons, file must be owned either by
50
* the user himself, or by root. Otherwise, don't grant access.
51
*/
52
if (fstat(fileno(fp), &sbuf)) {
53
return(FALSE);
54
}
55
56
if ((sbuf.st_uid != uid) && sbuf.st_uid) {
57
return(FALSE);
58
}
59
60
return(TRUE);
61
}
62
63
/*
64
* Given a Kerberos principal "principal", and a local username "luser",
65
* determine whether user is authorized to login according to the authorization
66
* files ~luser/.k5login" and ~luser/.k5users. Set *ok to TRUE if authorized,
67
* FALSE if not authorized. Return 0 if the authorization check succeeded
68
* (regardless of its result), non-zero if it encountered an error.
69
*/
70
71
krb5_error_code
72
krb5_authorization(krb5_context context, krb5_principal principal,
73
const char *luser, char *cmd, krb5_boolean *ok,
74
char **out_fcmd)
75
{
76
struct passwd *pwd;
77
char *princname = NULL;
78
int k5login_flag =0;
79
int k5users_flag =0;
80
krb5_boolean retbool =FALSE;
81
FILE * login_fp = 0, * users_fp = 0;
82
krb5_error_code retval = 0;
83
struct stat st_temp;
84
85
*ok =FALSE;
86
87
/* no account => no access */
88
if ((pwd = getpwnam(luser)) == NULL)
89
goto cleanup;
90
91
retval = krb5_unparse_name(context, principal, &princname);
92
if (retval)
93
return retval;
94
95
#ifdef DEBUG
96
printf("principal to be authorized %s\n", princname);
97
printf("login file: %s\n", k5login_path);
98
printf("users file: %s\n", k5users_path);
99
#endif
100
101
k5login_flag = stat(k5login_path, &st_temp);
102
k5users_flag = stat(k5users_path, &st_temp);
103
104
/* k5login and k5users must be owned by target user or root */
105
if (!k5login_flag){
106
login_fp = fopen(k5login_path, "r");
107
if (login_fp == NULL)
108
goto cleanup;
109
if (fowner(login_fp, pwd->pw_uid) == FALSE)
110
goto cleanup;
111
}
112
113
if (!k5users_flag){
114
users_fp = fopen(k5users_path, "r");
115
if (users_fp == NULL)
116
goto cleanup;
117
if (fowner(users_fp, pwd->pw_uid) == FALSE)
118
goto cleanup;
119
}
120
121
if (auth_debug){
122
fprintf(stderr,
123
"In krb5_authorization: if auth files exist -> can access\n");
124
}
125
126
/* if either file exists,
127
first see if the principal is in the login in file,
128
if it's not there check the k5users file */
129
130
if (!k5login_flag){
131
if (auth_debug)
132
fprintf(stderr,
133
"In krb5_authorization: principal to be authorized %s\n",
134
princname);
135
136
retval = k5login_lookup(login_fp, princname, &retbool);
137
if (retval)
138
goto cleanup;
139
if (retbool) {
140
if (cmd)
141
*out_fcmd = xstrdup(cmd);
142
}
143
}
144
145
if ((!k5users_flag) && (retbool == FALSE) ){
146
retval = k5users_lookup (users_fp, princname,
147
cmd, &retbool, out_fcmd);
148
if (retval)
149
goto cleanup;
150
}
151
152
if (k5login_flag && k5users_flag){
153
154
char * kuser = (char *) xcalloc (strlen(princname), sizeof(char));
155
if (!(krb5_aname_to_localname(context, principal,
156
strlen(princname), kuser))
157
&& (strcmp(kuser, luser) == 0)) {
158
retbool = TRUE;
159
}
160
161
free(kuser);
162
}
163
164
*ok =retbool;
165
166
cleanup:
167
if (users_fp != NULL)
168
fclose(users_fp);
169
if (login_fp != NULL)
170
fclose(login_fp);
171
free(princname);
172
return retval;
173
}
174
175
/***********************************************************
176
k5login_lookup looks for princname in file fp. Spaces
177
before the princaname (in the file ) are not ignored
178
spaces after the princname are ignored. If there are
179
any tokens after the principal name FALSE is returned.
180
181
***********************************************************/
182
183
krb5_error_code
184
k5login_lookup(FILE *fp, char *princname, krb5_boolean *found)
185
{
186
187
krb5_error_code retval;
188
char * line;
189
char * fprinc;
190
char * lp;
191
krb5_boolean loc_found = FALSE;
192
193
retval = get_line(fp, &line);
194
if (retval)
195
return retval;
196
197
while (line){
198
fprinc = get_first_token (line, &lp);
199
200
if (fprinc && (!strcmp(princname, fprinc))){
201
if( get_next_token (&lp) ){
202
free (line);
203
break; /* nothing should follow princname*/
204
}
205
else{
206
loc_found = TRUE;
207
free (line);
208
break;
209
}
210
}
211
212
free (line);
213
214
retval = get_line(fp, &line);
215
if (retval)
216
return retval;
217
}
218
219
220
*found = loc_found;
221
return 0;
222
223
}
224
225
/***********************************************************
226
k5users_lookup looks for princname in file fp. Spaces
227
before the princaname (in the file ) are not ignored
228
spaces after the princname are ignored.
229
230
authorization alg:
231
232
if princname is not found return false.
233
234
if princname is found{
235
if cmd == NULL then the file entry after principal
236
name must be nothing or *
237
238
if cmd !=NULL then entry must be matched (* is ok)
239
}
240
241
242
***********************************************************/
243
krb5_error_code
244
k5users_lookup(FILE *fp, char *princname, char *cmd,
245
krb5_boolean *found, char **out_fcmd)
246
{
247
krb5_error_code retval;
248
char * line;
249
char * fprinc, *fcmd;
250
char * lp;
251
char * loc_fcmd = NULL;
252
krb5_boolean loc_found = FALSE;
253
254
retval = get_line(fp, &line);
255
if (retval)
256
return retval;
257
258
while (line){
259
fprinc = get_first_token (line, &lp);
260
261
if (fprinc && (!strcmp(princname, fprinc))){
262
fcmd = get_next_token (&lp);
263
264
if ((fcmd) && (!strcmp(fcmd, PERMIT_ALL_COMMANDS))){
265
if (get_next_token(&lp) == NULL){
266
loc_fcmd =cmd ? xstrdup(cmd): NULL;
267
loc_found = TRUE;
268
}
269
free (line);
270
break;
271
}
272
273
if (cmd == NULL){
274
if (fcmd == NULL)
275
loc_found = TRUE;
276
free (line);
277
break;
278
279
}else{
280
if (fcmd != NULL) {
281
char * temp_rfcmd, *err;
282
krb5_boolean match;
283
do {
284
if(match_commands(fcmd,cmd,&match,
285
&temp_rfcmd, &err)){
286
if (auth_debug){
287
fprintf(stderr,"%s",err);
288
}
289
loc_fcmd = err;
290
break;
291
}else{
292
if (match == TRUE){
293
loc_fcmd = temp_rfcmd;
294
loc_found = TRUE;
295
break;
296
}
297
}
298
299
}while ((fcmd = get_next_token( &lp)));
300
}
301
free (line);
302
break;
303
}
304
}
305
306
free (line);
307
308
retval = get_line(fp, &line);
309
if (retval) {
310
return retval;
311
}
312
}
313
314
*out_fcmd = loc_fcmd;
315
*found = loc_found;
316
return 0;
317
318
}
319
320
321
/***********************************************
322
fcmd_resolve -
323
takes a command specified .k5users file and
324
resolves it into a full path name.
325
326
************************************************/
327
328
krb5_boolean
329
fcmd_resolve(char *fcmd, char ***out_fcmd, char **out_err)
330
{
331
char * err;
332
char ** tmp_fcmd = NULL;
333
char * path_ptr, *path;
334
char * lp, * tc;
335
int i=0;
336
krb5_boolean ok = FALSE;
337
338
tmp_fcmd = (char **) xcalloc (MAX_CMD, sizeof(char *));
339
340
if (*fcmd == '/'){ /* must be full path */
341
tmp_fcmd[0] = xstrdup(fcmd);
342
tmp_fcmd[1] = NULL;
343
*out_fcmd = tmp_fcmd;
344
tmp_fcmd = NULL;
345
}else{
346
/* must be either full path or just the cmd name */
347
if (strchr(fcmd, '/')){
348
asprintf(&err, _("Error: bad entry - %s in %s file, must be "
349
"either full path or just the cmd name\n"),
350
fcmd, KRB5_USERS_NAME);
351
*out_err = err;
352
goto cleanup;
353
}
354
355
#ifndef CMD_PATH
356
asprintf(&err, _("Error: bad entry - %s in %s file, since %s is just "
357
"the cmd name, CMD_PATH must be defined \n"),
358
fcmd, KRB5_USERS_NAME, fcmd);
359
*out_err = err;
360
goto cleanup;
361
#else
362
363
path = xstrdup (CMD_PATH);
364
path_ptr = path;
365
366
while ((*path_ptr == ' ') || (*path_ptr == '\t')) path_ptr ++;
367
368
tc = get_first_token (path_ptr, &lp);
369
370
if (! tc){
371
asprintf(&err, _("Error: bad entry - %s in %s file, CMD_PATH "
372
"contains no paths \n"), fcmd, KRB5_USERS_NAME);
373
*out_err = err;
374
goto cleanup;
375
}
376
377
i=0;
378
do{
379
if (*tc != '/'){ /* must be full path */
380
asprintf(&err, _("Error: bad path %s in CMD_PATH for %s must "
381
"start with '/' \n"), tc, KRB5_USERS_NAME );
382
*out_err = err;
383
goto cleanup;
384
}
385
386
tmp_fcmd[i] = xasprintf("%s/%s", tc, fcmd);
387
388
i++;
389
390
} while((tc = get_next_token (&lp)));
391
392
tmp_fcmd[i] = NULL;
393
*out_fcmd = tmp_fcmd;
394
tmp_fcmd = NULL;
395
#endif /* CMD_PATH */
396
}
397
398
ok = TRUE;
399
400
cleanup:
401
free_fcmd_list(tmp_fcmd);
402
return ok;
403
}
404
405
/********************************************
406
cmd_single - checks if cmd consists of a path
407
or a single token
408
409
********************************************/
410
411
krb5_boolean
412
cmd_single(char *cmd)
413
{
414
415
if ( ( strrchr( cmd, '/')) == NULL){
416
return TRUE;
417
}else{
418
return FALSE;
419
}
420
}
421
422
/********************************************
423
cmd_arr_cmp_postfix - compares a command with the postfix
424
of fcmd
425
********************************************/
426
427
int
428
cmd_arr_cmp_postfix(char **fcmd_arr, char *cmd)
429
{
430
char * temp_fcmd;
431
char *ptr;
432
int result =1;
433
int i = 0;
434
435
while(fcmd_arr[i]){
436
if ( (ptr = strrchr( fcmd_arr[i], '/')) == NULL){
437
temp_fcmd = fcmd_arr[i];
438
}else {
439
temp_fcmd = ptr + 1;
440
}
441
442
result = strcmp (temp_fcmd, cmd);
443
if (result == 0){
444
break;
445
}
446
i++;
447
}
448
449
return result;
450
451
452
}
453
454
/**********************************************
455
cmd_arr_cmp - checks if cmd matches any
456
of the fcmd entries.
457
458
**********************************************/
459
460
int
461
cmd_arr_cmp(char **fcmd_arr, char *cmd)
462
{
463
int result =1;
464
int i = 0;
465
466
while(fcmd_arr[i]){
467
result = strcmp (fcmd_arr[i], cmd);
468
if (result == 0){
469
break;
470
}
471
i++;
472
}
473
return result;
474
}
475
476
477
krb5_boolean
478
find_first_cmd_that_exists(char **fcmd_arr, char **cmd_out, char **err_out)
479
{
480
struct stat st_temp;
481
int i = 0;
482
krb5_boolean retbool= FALSE;
483
int j =0;
484
struct k5buf buf;
485
486
while(fcmd_arr[i]){
487
if (!stat (fcmd_arr[i], &st_temp )){
488
*cmd_out = xstrdup(fcmd_arr[i]);
489
retbool = TRUE;
490
break;
491
}
492
i++;
493
}
494
495
if (retbool == FALSE ){
496
k5_buf_init_dynamic(&buf);
497
k5_buf_add(&buf, _("Error: not found -> "));
498
for(j= 0; j < i; j ++)
499
k5_buf_add_fmt(&buf, " %s ", fcmd_arr[j]);
500
k5_buf_add(&buf, "\n");
501
*err_out = k5_buf_cstring(&buf);
502
if (*err_out == NULL) {
503
perror(prog_name);
504
exit(1);
505
}
506
}
507
508
509
return retbool;
510
}
511
512
/***************************************************************
513
returns 1 if there is an error, 0 if no error.
514
515
***************************************************************/
516
517
int
518
match_commands(char *fcmd, char *cmd, krb5_boolean *match,
519
char **cmd_out, char **err_out)
520
{
521
char ** fcmd_arr = NULL;
522
char * err;
523
char * cmd_temp;
524
int result = 1;
525
526
if(fcmd_resolve(fcmd, &fcmd_arr, &err )== FALSE ){
527
*err_out = err;
528
goto cleanup;
529
}
530
531
if (cmd_single( cmd ) == TRUE){
532
if (!cmd_arr_cmp_postfix(fcmd_arr, cmd)){ /* found */
533
if (!find_first_cmd_that_exists(fcmd_arr, &cmd_temp, &err)) {
534
*err_out = err;
535
goto cleanup;
536
}
537
538
*match = TRUE;
539
*cmd_out = cmd_temp;
540
} else {
541
*match = FALSE;
542
}
543
}else{
544
if (!cmd_arr_cmp(fcmd_arr, cmd)){ /* found */
545
*match = TRUE;
546
*cmd_out = xstrdup(cmd);
547
} else{
548
*match = FALSE;
549
}
550
}
551
552
result = 0;
553
554
cleanup:
555
free_fcmd_list(fcmd_arr);
556
return result;
557
}
558
559
/*********************************************************
560
get_line - returns a line of any length. out_line
561
is set to null if eof.
562
*********************************************************/
563
564
krb5_error_code
565
get_line(FILE *fp, char **out_line)
566
{
567
char * line, *r, *newline , *line_ptr;
568
int chunk_count = 1;
569
570
line = (char *) xcalloc (BUFSIZ, sizeof (char ));
571
line_ptr = line;
572
line[0] = '\0';
573
574
while (( r = fgets(line_ptr, BUFSIZ , fp)) != NULL){
575
newline = strchr(line_ptr, '\n');
576
if (newline) {
577
*newline = '\0';
578
break;
579
}
580
else {
581
chunk_count ++;
582
line = xrealloc(line, chunk_count * BUFSIZ);
583
584
line_ptr = line + (BUFSIZ -1) *( chunk_count -1) ;
585
}
586
}
587
588
if ((r == NULL) && (strlen(line) == 0)) {
589
*out_line = NULL;
590
}
591
else{
592
*out_line = line;
593
}
594
595
return 0;
596
}
597
598
/*******************************************************
599
get_first_token -
600
Expects a '\0' terminated input line .
601
If there are any spaces before the first token, they
602
will be returned as part of the first token.
603
604
Note: this routine reuses the space pointed to by line
605
******************************************************/
606
607
char *
608
get_first_token(char *line, char **lnext)
609
{
610
611
char * lptr, * out_ptr;
612
613
614
out_ptr = line;
615
lptr = line;
616
617
while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;
618
619
if (strlen(lptr) == 0) return NULL;
620
621
while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;
622
623
if (*lptr == '\0'){
624
*lnext = lptr;
625
} else{
626
*lptr = '\0';
627
*lnext = lptr + 1;
628
}
629
630
return out_ptr;
631
}
632
/**********************************************************
633
get_next_token -
634
returns the next token pointed to by *lnext.
635
returns NULL if there is no more tokens.
636
Note: that this function modifies the stream
637
pointed to by *lnext and does not allocate
638
space for the returned tocken. It also advances
639
lnext to the next tocken.
640
**********************************************************/
641
642
char *
643
get_next_token (char **lnext)
644
{
645
char * lptr, * out_ptr;
646
647
648
lptr = *lnext;
649
650
while (( *lptr == ' ') || (*lptr == '\t')) lptr ++;
651
652
if (strlen(lptr) == 0) return NULL;
653
654
out_ptr = lptr;
655
656
while (( *lptr != ' ') && (*lptr != '\t') && (*lptr != '\0')) lptr ++;
657
658
if (*lptr == '\0'){
659
*lnext = lptr;
660
} else{
661
*lptr = '\0';
662
*lnext = lptr + 1;
663
}
664
665
return out_ptr;
666
}
667
668
void
669
init_auth_names(char *pw_dir)
670
{
671
const char *sep;
672
int r1, r2;
673
674
sep = ((strlen(pw_dir) == 1) && (*pw_dir == '/')) ? "" : "/";
675
r1 = snprintf(k5login_path, sizeof(k5login_path), "%s%s%s",
676
pw_dir, sep, KRB5_LOGIN_NAME);
677
r2 = snprintf(k5users_path, sizeof(k5users_path), "%s%s%s",
678
pw_dir, sep, KRB5_USERS_NAME);
679
if (SNPRINTF_OVERFLOW(r1, sizeof(k5login_path)) ||
680
SNPRINTF_OVERFLOW(r2, sizeof(k5users_path))) {
681
fprintf(stderr, _("home directory name `%s' too long, can't search "
682
"for .k5login\n"), pw_dir);
683
exit (1);
684
}
685
}
686
687