Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/clients/ksu/main.c
34889 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
#include "adm_proto.h"
31
#include <sys/types.h>
32
#include <sys/wait.h>
33
#include <signal.h>
34
#include <grp.h>
35
36
/* globals */
37
char * prog_name;
38
int auth_debug =0;
39
char k5login_path[MAXPATHLEN];
40
char k5users_path[MAXPATHLEN];
41
char * gb_err = NULL;
42
int quiet = 0;
43
/***********/
44
45
#define KS_TEMPORARY_CACHE "MEMORY:_ksu"
46
#define KS_TEMPORARY_PRINC "_ksu/_ksu@_ksu"
47
#define _DEF_CSH "/bin/csh"
48
static int set_env_var (char *, char *);
49
static void sweep_up (krb5_context, krb5_ccache);
50
static char * ontty (void);
51
static krb5_error_code init_ksu_context(krb5_context *);
52
static krb5_error_code set_ccname_env(krb5_context, krb5_ccache);
53
static void print_status( const char *fmt, ...)
54
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
55
__attribute__ ((__format__ (__printf__, 1, 2)))
56
#endif
57
;
58
static krb5_error_code resolve_target_cache(krb5_context ksu_context,
59
krb5_principal princ,
60
krb5_ccache *ccache_out,
61
krb5_boolean *ccache_reused);
62
63
/* Note -e and -a options are mutually exclusive */
64
/* insure the proper specification of target user as well as catching
65
ill specified arguments to commands */
66
67
void
68
usage(void)
69
{
70
fprintf(stderr,
71
_("Usage: %s [target user] [-n principal] [-c source cachename] "
72
"[-k] [-r time] [-p|-P] [-f|-F] [-l lifetime] [-zZ] [-q] "
73
"[-e command [args... ] ] [-a [args... ] ]\n"), prog_name);
74
}
75
76
/* for Ultrix and friends ... */
77
#ifndef MAXHOSTNAMELEN
78
#define MAXHOSTNAMELEN 64
79
#endif
80
81
/* These are file static so sweep_up can get to them*/
82
static uid_t source_uid, target_uid;
83
84
int
85
main(int argc, char ** argv)
86
{
87
int hp =0;
88
int some_rest_copy = 0;
89
int all_rest_copy = 0;
90
char *localhostname = NULL;
91
krb5_get_init_creds_opt *options = NULL;
92
int option=0;
93
int statusp=0;
94
krb5_error_code retval = 0;
95
krb5_principal client = NULL, tmp_princ = NULL;
96
krb5_ccache cc_tmp = NULL, cc_target = NULL;
97
krb5_context ksu_context;
98
char * cc_target_tag = NULL;
99
char * target_user = NULL;
100
char * source_user;
101
102
krb5_ccache cc_source = NULL;
103
const char * cc_source_tag = NULL;
104
char * cmd = NULL, * exec_cmd = NULL;
105
int errflg = 0;
106
krb5_boolean auth_val;
107
krb5_boolean authorization_val = FALSE;
108
int path_passwd = 0;
109
int done =0,i,j;
110
uid_t ruid = getuid ();
111
struct passwd *pwd=NULL, *target_pwd ;
112
char * shell;
113
char ** params;
114
int keep_target_cache = 0;
115
int child_pid, child_pgrp, ret_pid;
116
int pargc;
117
char ** pargv;
118
krb5_boolean stored = FALSE, cc_reused = FALSE, given_princ = FALSE;
119
krb5_boolean zero_password;
120
krb5_boolean restrict_creds;
121
krb5_deltat lifetime, rlife;
122
123
if (argc == 0)
124
exit(1);
125
126
params = (char **) xcalloc (2, sizeof (char *));
127
params[1] = NULL;
128
129
unsetenv ("KRB5_CONFIG");
130
131
retval = init_ksu_context(&ksu_context);
132
if (retval) {
133
com_err(argv[0], retval, _("while initializing krb5"));
134
exit(1);
135
}
136
137
retval = krb5_get_init_creds_opt_alloc(ksu_context, &options);
138
if (retval) {
139
com_err(argv[0], retval, _("while initializing krb5"));
140
exit(1);
141
}
142
143
if (strrchr(argv[0], '/'))
144
argv[0] = strrchr(argv[0], '/')+1;
145
prog_name = argv[0];
146
if (strlen (prog_name) > 50) {
147
/* this many chars *after* last / ?? */
148
com_err(prog_name, 0,
149
_("program name too long - quitting to avoid triggering "
150
"system logging bugs"));
151
exit (1);
152
}
153
154
155
#ifndef LOG_NDELAY
156
#define LOG_NDELAY 0
157
#endif
158
159
#ifndef LOG_AUTH /* 4.2 syslog */
160
openlog(prog_name, LOG_PID|LOG_NDELAY);
161
#else
162
openlog(prog_name, LOG_PID | LOG_NDELAY, LOG_AUTH);
163
#endif /* 4.2 syslog */
164
165
166
if (( argc == 1) || (argv[1][0] == '-')){
167
target_user = xstrdup("root");
168
pargc = argc;
169
pargv = argv;
170
} else {
171
target_user = xstrdup(argv[1]);
172
pargc = argc -1;
173
174
if ((pargv =(char **) calloc(pargc +1,sizeof(char *)))==NULL){
175
com_err(prog_name, errno, _("while allocating memory"));
176
exit(1);
177
}
178
179
pargv[pargc] = NULL;
180
pargv[0] = argv[0];
181
182
for(i =1; i< pargc; i ++){
183
pargv[i] = argv[i + 1];
184
}
185
}
186
187
if (krb5_seteuid (ruid)) {
188
com_err (prog_name, errno, _("while setting euid to source user"));
189
exit (1);
190
}
191
while (!done &&
192
(option = getopt(pargc, pargv,"n:c:r:a:zZDfFpPkql:e:")) != -1) {
193
switch (option) {
194
case 'r':
195
if (strlen (optarg) >= 14)
196
optarg = "bad-time";
197
retval = krb5_string_to_deltat(optarg, &rlife);
198
if (retval != 0 || rlife == 0) {
199
fprintf(stderr, _("Bad lifetime value (%s hours?)\n"), optarg);
200
errflg++;
201
}
202
krb5_get_init_creds_opt_set_renew_life(options, rlife);
203
break;
204
case 'a':
205
/* when integrating this remember to pass in pargc, pargv and
206
take care of params argument */
207
optind --;
208
if (auth_debug){printf("Before get_params optind=%d\n", optind);}
209
210
if ((retval = get_params( & optind, pargc, pargv, &params))){
211
com_err(prog_name, retval, _("when gathering parameters"));
212
errflg++;
213
}
214
if(auth_debug){ printf("After get_params optind=%d\n", optind);}
215
done = 1;
216
break;
217
case 'p':
218
krb5_get_init_creds_opt_set_proxiable(options, 1);
219
break;
220
case 'P':
221
krb5_get_init_creds_opt_set_proxiable(options, 0);
222
break;
223
case 'f':
224
krb5_get_init_creds_opt_set_forwardable(options, 1);
225
break;
226
case 'F':
227
krb5_get_init_creds_opt_set_forwardable(options, 0);
228
break;
229
case 'k':
230
keep_target_cache =1;
231
break;
232
case 'q':
233
quiet =1;
234
break;
235
case 'l':
236
if (strlen (optarg) >= 14)
237
optarg = "bad-time";
238
retval = krb5_string_to_deltat(optarg, &lifetime);
239
if (retval != 0 || lifetime == 0) {
240
fprintf(stderr, _("Bad lifetime value (%s hours?)\n"), optarg);
241
errflg++;
242
}
243
krb5_get_init_creds_opt_set_tkt_life(options, lifetime);
244
break;
245
case 'n':
246
if ((retval = krb5_parse_name(ksu_context, optarg, &client))){
247
com_err(prog_name, retval, _("when parsing name %s"), optarg);
248
errflg++;
249
}
250
given_princ = TRUE;
251
break;
252
#ifdef DEBUG
253
case 'D':
254
auth_debug = 1;
255
break;
256
#endif
257
case 'z':
258
some_rest_copy = 1;
259
if(all_rest_copy) {
260
fprintf(stderr,
261
_("-z option is mutually exclusive with -Z.\n"));
262
errflg++;
263
}
264
break;
265
case 'Z':
266
all_rest_copy = 1;
267
if(some_rest_copy) {
268
fprintf(stderr,
269
_("-Z option is mutually exclusive with -z.\n"));
270
errflg++;
271
}
272
break;
273
case 'c':
274
if (cc_source_tag == NULL) {
275
cc_source_tag = xstrdup(optarg);
276
if (!ks_ccache_name_is_initialized(ksu_context,
277
cc_source_tag)) {
278
com_err(prog_name, errno,
279
_("while looking for credentials cache %s"),
280
cc_source_tag);
281
exit(1);
282
}
283
} else {
284
fprintf(stderr, _("Only one -c option allowed\n"));
285
errflg++;
286
}
287
break;
288
case 'e':
289
cmd = xstrdup(optarg);
290
if(auth_debug){printf("Before get_params optind=%d\n", optind);}
291
if ((retval = get_params( & optind, pargc, pargv, &params))){
292
com_err(prog_name, retval, _("when gathering parameters"));
293
errflg++;
294
}
295
if(auth_debug){printf("After get_params optind=%d\n", optind);}
296
done = 1;
297
298
if (auth_debug){
299
fprintf(stderr,"Command to be executed: %s\n", cmd);
300
}
301
break;
302
case '?':
303
default:
304
errflg++;
305
break;
306
}
307
}
308
309
if (errflg) {
310
usage();
311
exit(2);
312
}
313
314
if (optind != pargc ){
315
usage();
316
exit(2);
317
}
318
319
if (auth_debug){
320
for(j=1; params[j] != NULL; j++){
321
fprintf (stderr,"params[%d]= %s\n", j,params[j]);
322
}
323
}
324
325
/***********************************/
326
source_user = getlogin(); /*checks for the the login name in /etc/utmp*/
327
328
/* verify that that the user exists and get his passwd structure */
329
330
if (source_user == NULL ||(pwd = getpwnam(source_user)) == NULL ||
331
pwd->pw_uid != ruid){
332
pwd = getpwuid(ruid);
333
}
334
335
if (pwd == NULL) {
336
fprintf(stderr, _("ksu: who are you?\n"));
337
exit(1);
338
}
339
if (pwd->pw_uid != ruid) {
340
fprintf (stderr, _("Your uid doesn't match your passwd entry?!\n"));
341
exit (1);
342
}
343
/* Okay, now we have *some* passwd entry that matches the
344
current real uid. */
345
346
/* allocate space and copy the usernamane there */
347
source_user = xstrdup(pwd->pw_name);
348
source_uid = pwd->pw_uid;
349
350
if (!strcmp(SOURCE_USER_LOGIN, target_user)){
351
target_user = xstrdup (source_user);
352
}
353
354
if ((target_pwd = getpwnam(target_user)) == NULL){
355
fprintf(stderr, _("ksu: unknown login %s\n"), target_user);
356
exit(1);
357
}
358
target_uid = target_pwd->pw_uid;
359
360
init_auth_names(target_pwd->pw_dir);
361
362
/***********************************/
363
364
if (cc_source_tag == NULL){
365
cc_source_tag = krb5_cc_default_name(ksu_context);
366
if (cc_source_tag == NULL) {
367
fprintf(stderr, _("ksu: failed to get default ccache name\n"));
368
exit(1);
369
}
370
}
371
372
/* get a handle for the cache */
373
if ((retval = krb5_cc_resolve(ksu_context, cc_source_tag, &cc_source))){
374
com_err(prog_name, retval, _("while getting source cache"));
375
exit(1);
376
}
377
378
if ((retval = get_best_princ_for_target(ksu_context, source_uid,
379
target_uid, source_user,
380
target_user, cc_source,
381
options, cmd, localhostname,
382
&client, &hp))){
383
com_err(prog_name,retval, _("while selecting the best principal"));
384
exit(1);
385
}
386
387
/* We may be running as either source or target, depending on
388
what happened; become source.*/
389
if ( geteuid() != source_uid) {
390
if (krb5_seteuid(0) || krb5_seteuid(source_uid) ) {
391
com_err(prog_name, errno, _("while returning to source uid after "
392
"finding best principal"));
393
exit(1);
394
}
395
}
396
397
if (auth_debug){
398
if (hp){
399
fprintf(stderr,
400
"GET_best_princ_for_target result: NOT AUTHORIZED\n");
401
}else{
402
fprintf(stderr,
403
"GET_best_princ_for_target result-best principal ");
404
plain_dump_principal (ksu_context, client);
405
fprintf(stderr,"\n");
406
}
407
}
408
409
if (hp){
410
if (gb_err) fprintf(stderr, "%s", gb_err);
411
fprintf(stderr, _("account %s: authorization failed\n"), target_user);
412
413
if (cmd != NULL) {
414
syslog(LOG_WARNING,
415
"Account %s: authorization for %s for execution of %s failed",
416
target_user, source_user, cmd);
417
} else {
418
syslog(LOG_WARNING, "Account %s: authorization of %s failed",
419
target_user, source_user);
420
}
421
422
exit(1);
423
}
424
425
if (auth_debug)
426
fprintf(stderr, " source cache = %s\n", cc_source_tag);
427
428
/*
429
* After proper authentication and authorization, populate a cache for the
430
* target user.
431
*/
432
433
/*
434
* We read the set of creds we want to copy from the source ccache as the
435
* source uid, become root for authentication, and then become the target
436
* user to handle authorization and creating the target user's cache.
437
*/
438
439
/* if root ksu's to a regular user, then
440
then only the credentials for that particular user
441
should be copied */
442
443
restrict_creds = (source_uid == 0) && (target_uid != 0);
444
retval = krb5_parse_name(ksu_context, KS_TEMPORARY_PRINC, &tmp_princ);
445
if (retval) {
446
com_err(prog_name, retval, _("while parsing temporary name"));
447
exit(1);
448
}
449
retval = krb5_cc_resolve(ksu_context, KS_TEMPORARY_CACHE, &cc_tmp);
450
if (retval) {
451
com_err(prog_name, retval, _("while creating temporary cache"));
452
exit(1);
453
}
454
retval = krb5_ccache_copy(ksu_context, cc_source, tmp_princ, cc_tmp,
455
restrict_creds, client, &stored);
456
if (retval) {
457
com_err(prog_name, retval, _("while copying cache %s to %s"),
458
krb5_cc_get_name(ksu_context, cc_source), KS_TEMPORARY_CACHE);
459
exit(1);
460
}
461
krb5_cc_close(ksu_context, cc_source);
462
463
krb5_get_init_creds_opt_set_out_ccache(ksu_context, options, cc_tmp);
464
465
/* Become root for authentication*/
466
467
if (krb5_seteuid(0)) {
468
com_err(prog_name, errno, _("while reclaiming root uid"));
469
exit(1);
470
}
471
472
if ((source_uid == 0) || (target_uid == source_uid)){
473
#ifdef GET_TGT_VIA_PASSWD
474
if (!all_rest_copy && given_princ && client != NULL && !stored) {
475
fprintf(stderr, _("WARNING: Your password may be exposed if you "
476
"enter it here and are logged\n"));
477
fprintf(stderr, _(" in remotely using an unsecure "
478
"(non-encrypted) channel.\n"));
479
if (ksu_get_tgt_via_passwd(ksu_context, client, options,
480
&zero_password, NULL) == FALSE) {
481
482
if (zero_password == FALSE){
483
fprintf(stderr, _("Goodbye\n"));
484
exit(1);
485
}
486
487
fprintf(stderr, _("Could not get a tgt for "));
488
plain_dump_principal (ksu_context, client);
489
fprintf(stderr, "\n");
490
491
}
492
stored = TRUE;
493
}
494
#endif /* GET_TGT_VIA_PASSWD */
495
}
496
497
/* if the user is root or same uid then authentication is not necessary,
498
root gets in automatically */
499
500
if (source_uid && (source_uid != target_uid)) {
501
char * client_name;
502
503
auth_val = krb5_auth_check(ksu_context, client, localhostname,
504
options, target_user, cc_tmp,
505
&path_passwd, target_uid);
506
507
/* if Kerberos authentication failed then exit */
508
if (auth_val ==FALSE){
509
fprintf(stderr, _("Authentication failed.\n"));
510
syslog(LOG_WARNING, "'%s %s' authentication failed for %s%s",
511
prog_name,target_user,source_user,ontty());
512
exit(1);
513
}
514
stored = TRUE;
515
516
if ((retval = krb5_unparse_name(ksu_context, client, &client_name))) {
517
com_err(prog_name, retval, _("When unparsing name"));
518
exit(1);
519
}
520
521
print_status(_("Authenticated %s\n"), client_name);
522
syslog(LOG_NOTICE,"'%s %s' authenticated %s for %s%s",
523
prog_name,target_user,client_name,
524
source_user,ontty());
525
526
/* Run authorization as target.*/
527
if (krb5_seteuid(target_uid)) {
528
com_err(prog_name, errno, _("while switching to target for "
529
"authorization check"));
530
exit(1);
531
}
532
533
if ((retval = krb5_authorization(ksu_context, client,target_user,
534
cmd, &authorization_val, &exec_cmd))){
535
com_err(prog_name,retval, _("while checking authorization"));
536
krb5_seteuid(0); /*So we have some chance of sweeping up*/
537
exit(1);
538
}
539
540
if (krb5_seteuid(0)) {
541
com_err(prog_name, errno, _("while switching back from target "
542
"after authorization check"));
543
exit(1);
544
}
545
if (authorization_val == TRUE){
546
547
if (cmd) {
548
print_status(_("Account %s: authorization for %s for "
549
"execution of\n"), target_user, client_name);
550
print_status(_(" %s successful\n"), exec_cmd);
551
syslog(LOG_NOTICE,
552
"Account %s: authorization for %s for execution of %s successful",
553
target_user, client_name, exec_cmd);
554
555
}else{
556
print_status(_("Account %s: authorization for %s "
557
"successful\n"), target_user, client_name);
558
syslog(LOG_NOTICE,
559
"Account %s: authorization for %s successful",
560
target_user, client_name);
561
}
562
}else {
563
if (cmd){
564
if (exec_cmd){ /* was used to pass back the error msg */
565
fprintf(stderr, "%s", exec_cmd );
566
syslog(LOG_WARNING, "%s",exec_cmd);
567
}
568
fprintf(stderr, _("Account %s: authorization for %s for "
569
"execution of %s failed\n"),
570
target_user, client_name, cmd );
571
syslog(LOG_WARNING,
572
"Account %s: authorization for %s for execution of %s failed",
573
target_user, client_name, cmd );
574
575
}else{
576
fprintf(stderr, _("Account %s: authorization of %s failed\n"),
577
target_user, client_name);
578
syslog(LOG_WARNING,
579
"Account %s: authorization of %s failed",
580
target_user, client_name);
581
582
}
583
584
exit(1);
585
}
586
}
587
588
if( some_rest_copy){
589
retval = krb5_ccache_filter(ksu_context, cc_tmp, client);
590
if (retval) {
591
com_err(prog_name,retval, _("while calling cc_filter"));
592
exit(1);
593
}
594
}
595
596
if (all_rest_copy){
597
retval = krb5_cc_initialize(ksu_context, cc_tmp, tmp_princ);
598
if (retval) {
599
com_err(prog_name, retval, _("while erasing target cache"));
600
exit(1);
601
}
602
stored = FALSE;
603
}
604
605
/* get the shell of the user, this will be the shell used by su */
606
target_pwd = getpwnam(target_user);
607
608
if (target_pwd->pw_shell)
609
shell = xstrdup(target_pwd->pw_shell);
610
else {
611
shell = _DEF_CSH; /* default is cshell */
612
}
613
614
#ifdef HAVE_GETUSERSHELL
615
616
/* insist that the target login uses a standard shell (root is omitted) */
617
618
if (!standard_shell(target_pwd->pw_shell) && source_uid) {
619
fprintf(stderr, _("ksu: permission denied (shell).\n"));
620
exit(1);
621
}
622
#endif /* HAVE_GETUSERSHELL */
623
624
if (target_pwd->pw_uid){
625
626
if(set_env_var("USER", target_pwd->pw_name)){
627
fprintf(stderr,
628
_("ksu: couldn't set environment variable USER\n"));
629
exit(1);
630
}
631
}
632
633
if(set_env_var( "HOME", target_pwd->pw_dir)){
634
fprintf(stderr, _("ksu: couldn't set environment variable HOME\n"));
635
exit(1);
636
}
637
638
if(set_env_var( "SHELL", shell)){
639
fprintf(stderr, _("ksu: couldn't set environment variable SHELL\n"));
640
exit(1);
641
}
642
643
/* set permissions */
644
if (setgid(target_pwd->pw_gid) < 0) {
645
perror("ksu: setgid");
646
exit(1);
647
}
648
649
if (initgroups(target_user, target_pwd->pw_gid)) {
650
fprintf(stderr, _("ksu: initgroups failed.\n"));
651
exit(1);
652
}
653
654
if ( ! strcmp(target_user, source_user)){
655
print_status(_("Leaving uid as %s (%ld)\n"),
656
target_user, (long) target_pwd->pw_uid);
657
}else{
658
print_status(_("Changing uid to %s (%ld)\n"),
659
target_user, (long) target_pwd->pw_uid);
660
}
661
662
#ifdef HAVE_SETLUID
663
/*
664
* If we're on a system which keeps track of login uids, then
665
* set the login uid. If this fails this opens up a problem on DEC OSF
666
* with C2 enabled.
667
*/
668
if (setluid((uid_t) pwd->pw_uid) < 0) {
669
perror("setluid");
670
exit(1);
671
}
672
#endif /* HAVE_SETLUID */
673
674
if (setuid(target_pwd->pw_uid) < 0) {
675
perror("ksu: setuid");
676
exit(1);
677
}
678
679
retval = resolve_target_cache(ksu_context, client, &cc_target, &cc_reused);
680
if (retval)
681
exit(1);
682
retval = krb5_cc_get_full_name(ksu_context, cc_target, &cc_target_tag);
683
if (retval) {
684
com_err(prog_name, retval, _("while getting name of target ccache"));
685
sweep_up(ksu_context, cc_target);
686
exit(1);
687
}
688
if (auth_debug)
689
fprintf(stderr, " target cache = %s\n", cc_target_tag);
690
if (cc_reused)
691
keep_target_cache = TRUE;
692
693
if (stored) {
694
retval = krb5_ccache_copy(ksu_context, cc_tmp, client, cc_target,
695
FALSE, client, &stored);
696
if (retval) {
697
com_err(prog_name, retval, _("while copying cache %s to %s"),
698
KS_TEMPORARY_CACHE, cc_target_tag);
699
exit(1);
700
}
701
702
if (!ks_ccache_is_initialized(ksu_context, cc_target)) {
703
com_err(prog_name, errno,
704
_("%s does not have correct permissions for %s, "
705
"%s aborted"), target_user, cc_target_tag, prog_name);
706
exit(1);
707
}
708
}
709
710
krb5_free_string(ksu_context, cc_target_tag);
711
712
/* Set the cc env name to target. */
713
retval = set_ccname_env(ksu_context, cc_target);
714
if (retval != 0) {
715
sweep_up(ksu_context, cc_target);
716
exit(1);
717
}
718
719
if (cmd){
720
if ((source_uid == 0) || (source_uid == target_uid )){
721
exec_cmd = cmd;
722
}
723
724
if( !exec_cmd){
725
fprintf(stderr, _("Internal error: command %s did not get "
726
"resolved\n"), cmd);
727
exit(1);
728
}
729
730
params[0] = exec_cmd;
731
}
732
else{
733
params[0] = shell;
734
}
735
736
if (auth_debug){
737
fprintf(stderr, "program to be execed %s\n",params[0]);
738
}
739
740
if( keep_target_cache ) {
741
execv(params[0], params);
742
com_err(prog_name, errno, _("while trying to execv %s"), params[0]);
743
sweep_up(ksu_context, cc_target);
744
exit(1);
745
}else{
746
statusp = 1;
747
switch ((child_pid = fork())) {
748
default:
749
if (auth_debug){
750
printf(" The child pid is %ld\n", (long) child_pid);
751
printf(" The parent pid is %ld\n", (long) getpid());
752
}
753
while ((ret_pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) {
754
if (WIFSTOPPED(statusp)) {
755
child_pgrp = tcgetpgrp(1);
756
kill(getpid(), SIGSTOP);
757
tcsetpgrp(1, child_pgrp);
758
kill(child_pid, SIGCONT);
759
statusp = 1;
760
continue;
761
}
762
break;
763
}
764
if (auth_debug){
765
printf("The exit status of the child is %d\n", statusp);
766
}
767
if (ret_pid == -1) {
768
com_err(prog_name, errno, _("while calling waitpid"));
769
}
770
sweep_up(ksu_context, cc_target);
771
exit (WIFEXITED(statusp) ? WEXITSTATUS(statusp) : 1);
772
case -1:
773
com_err(prog_name, errno, _("while trying to fork."));
774
sweep_up(ksu_context, cc_target);
775
exit (1);
776
case 0:
777
execv(params[0], params);
778
com_err(prog_name, errno, _("while trying to execv %s"),
779
params[0]);
780
exit (1);
781
}
782
}
783
}
784
785
static krb5_error_code
786
init_ksu_context(krb5_context *context_out)
787
{
788
krb5_error_code retval;
789
const char *env_ccname;
790
krb5_context context;
791
792
*context_out = NULL;
793
794
retval = krb5_init_secure_context(&context);
795
if (retval)
796
return retval;
797
798
/* We want to obey KRB5CCNAME in this context even though this is a setuid
799
* program. (It will only be used when operating as the real uid.) */
800
env_ccname = getenv(KRB5_ENV_CCNAME);
801
if (env_ccname != NULL) {
802
retval = krb5_cc_set_default_name(context, env_ccname);
803
if (retval) {
804
krb5_free_context(context);
805
return retval;
806
}
807
}
808
809
*context_out = context;
810
return 0;
811
}
812
813
/* Set KRB5CCNAME in the environment to point to ccache. Print an error
814
* message on failure. */
815
static krb5_error_code
816
set_ccname_env(krb5_context ksu_context, krb5_ccache ccache)
817
{
818
krb5_error_code retval;
819
char *ccname;
820
821
retval = krb5_cc_get_full_name(ksu_context, ccache, &ccname);
822
if (retval) {
823
com_err(prog_name, retval, _("while reading cache name from ccache"));
824
return retval;
825
}
826
if (set_env_var(KRB5_ENV_CCNAME, ccname)) {
827
retval = errno;
828
fprintf(stderr,
829
_("ksu: couldn't set environment variable %s\n"),
830
KRB5_ENV_CCNAME);
831
}
832
krb5_free_string(ksu_context, ccname);
833
return retval;
834
}
835
836
/*
837
* Get the configured default ccache name. Unset KRB5CCNAME and force a
838
* recomputation so we don't use values for the source user. Print an error
839
* message on failure.
840
*/
841
static krb5_error_code
842
get_configured_defccname(krb5_context context, char **target_out)
843
{
844
krb5_error_code retval;
845
const char *defname;
846
char *target = NULL;
847
848
*target_out = NULL;
849
850
unsetenv(KRB5_ENV_CCNAME);
851
852
/* Make sure we don't have a cached value for a different uid. */
853
retval = krb5_cc_set_default_name(context, NULL);
854
if (retval != 0) {
855
com_err(prog_name, retval, _("while resetting target ccache name"));
856
return retval;
857
}
858
859
defname = krb5_cc_default_name(context);
860
if (defname != NULL) {
861
if (strchr(defname, ':') != NULL) {
862
target = strdup(defname);
863
} else {
864
if (asprintf(&target, "FILE:%s", defname) < 0)
865
target = NULL;
866
}
867
}
868
if (target == NULL) {
869
com_err(prog_name, ENOMEM, _("while determining target ccache name"));
870
return ENOMEM;
871
}
872
*target_out = target;
873
return 0;
874
}
875
876
/* Determine where the target user's creds should be stored. Print an error
877
* message on failure. */
878
static krb5_error_code
879
resolve_target_cache(krb5_context context, krb5_principal princ,
880
krb5_ccache *ccache_out, krb5_boolean *ccache_reused)
881
{
882
krb5_error_code retval;
883
krb5_boolean switchable, reused = FALSE;
884
krb5_ccache ccache = NULL;
885
char *sep, *ccname = NULL, *sym = NULL, *target;
886
887
*ccache_out = NULL;
888
*ccache_reused = FALSE;
889
890
retval = get_configured_defccname(context, &target);
891
if (retval != 0)
892
return retval;
893
894
/* Check if the configured default name uses a switchable type. */
895
sep = strchr(target, ':');
896
*sep = '\0';
897
switchable = krb5_cc_support_switch(context, target);
898
*sep = ':';
899
900
if (!switchable) {
901
/* Try to avoid destroying an in-use target ccache by coming up with
902
* the name of a cache that doesn't exist yet. */
903
do {
904
free(ccname);
905
retval = gen_sym(context, &sym);
906
if (retval) {
907
com_err(prog_name, retval,
908
_("while generating part of the target ccache name"));
909
goto cleanup;
910
}
911
if (asprintf(&ccname, "%s.%s", target, sym) < 0) {
912
retval = ENOMEM;
913
free(sym);
914
com_err(prog_name, retval, _("while allocating memory for the "
915
"target ccache name"));
916
goto cleanup;
917
}
918
free(sym);
919
} while (ks_ccache_name_is_initialized(context, ccname));
920
retval = krb5_cc_resolve(context, ccname, &ccache);
921
free(ccname);
922
} else {
923
/* Look for a cache in the collection that we can reuse. */
924
retval = krb5_cc_cache_match(context, princ, &ccache);
925
if (retval == 0) {
926
reused = TRUE;
927
} else {
928
/* There isn't one, so create a new one. */
929
*sep = '\0';
930
retval = krb5_cc_new_unique(context, target, NULL, &ccache);
931
*sep = ':';
932
if (retval) {
933
com_err(prog_name, retval,
934
_("while creating new target ccache"));
935
goto cleanup;
936
}
937
retval = krb5_cc_initialize(context, ccache, princ);
938
if (retval) {
939
com_err(prog_name, retval,
940
_("while initializing target cache"));
941
goto cleanup;
942
}
943
}
944
}
945
946
*ccache_out = ccache;
947
*ccache_reused = reused;
948
949
cleanup:
950
free(target);
951
return retval;
952
}
953
954
#ifdef HAVE_GETUSERSHELL
955
956
int
957
standard_shell(char *sh)
958
{
959
char *cp;
960
961
while ((cp = getusershell()) != NULL)
962
if (!strcmp(cp, sh))
963
return (1);
964
return (0);
965
}
966
967
#endif /* HAVE_GETUSERSHELL */
968
969
static char *
970
ontty(void)
971
{
972
char *p;
973
static char buf[MAXPATHLEN + 5];
974
int result;
975
976
buf[0] = 0;
977
if ((p = ttyname(STDERR_FILENO))) {
978
result = snprintf(buf, sizeof(buf), " on %s", p);
979
if (SNPRINTF_OVERFLOW(result, sizeof(buf))) {
980
fprintf(stderr, _("terminal name %s too long\n"), p);
981
exit (1);
982
}
983
}
984
return (buf);
985
}
986
987
static int
988
set_env_var(char *name, char *value)
989
{
990
char * env_var_buf;
991
992
asprintf(&env_var_buf,"%s=%s",name, value);
993
return putenv(env_var_buf);
994
995
}
996
997
static void
998
sweep_up(krb5_context context, krb5_ccache cc)
999
{
1000
krb5_error_code retval;
1001
1002
krb5_seteuid(0);
1003
if (krb5_seteuid(target_uid) < 0) {
1004
com_err(prog_name, errno,
1005
_("while changing to target uid for destroying ccache"));
1006
exit(1);
1007
}
1008
1009
if (ks_ccache_is_initialized(context, cc)) {
1010
if ((retval = krb5_cc_destroy(context, cc)))
1011
com_err(prog_name, retval, _("while destroying cache"));
1012
}
1013
}
1014
1015
/*****************************************************************
1016
get_params is to be called for the -a option or -e option to
1017
collect all params passed in for the shell or for
1018
cmd. An array is returned containing all params.
1019
optindex is incremented accordingly and the first
1020
element in the returned array is reserved for the
1021
name of the command to be executed or the name of the
1022
shell.
1023
*****************************************************************/
1024
1025
krb5_error_code
1026
get_params(int *optindex, int pargc, char **pargv, char ***params)
1027
{
1028
1029
int i,j;
1030
char ** ret_params;
1031
int size = pargc - *optindex + 2;
1032
1033
if ((ret_params = (char **) calloc(size, sizeof (char *)))== NULL ){
1034
return ENOMEM;
1035
}
1036
1037
for (i = *optindex, j=1; i < pargc; i++,j++){
1038
ret_params[j] = pargv[i];
1039
*optindex = *optindex + 1;
1040
}
1041
1042
ret_params[size-1] = NULL;
1043
*params = ret_params;
1044
return 0;
1045
}
1046
1047
static
1048
void print_status(const char *fmt, ...)
1049
{
1050
va_list ap;
1051
if (! quiet){
1052
va_start(ap, fmt);
1053
vfprintf(stderr, fmt, ap);
1054
va_end(ap);
1055
}
1056
}
1057
1058
krb5_error_code
1059
ksu_tgtname(krb5_context context, const krb5_data *server,
1060
const krb5_data *client, krb5_principal *tgtprinc)
1061
{
1062
return krb5_build_principal_ext(context, tgtprinc, client->length, client->data,
1063
KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
1064
server->length, server->data,
1065
0);
1066
}
1067
1068