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