-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalife.c
897 lines (836 loc) · 31.8 KB
/
calife.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
/** Fichier calife.c
**
** SU ameliore dans ce sens qu'il consulte une database protegee dans
** ADMIN_DB/auth) afin de savoir si l'utilisateur est authorise a devenir root
** ou un autre utilisateur. Si oui, alors on lance un shell analogue a celui
** de l'utilisateur, sinon on lance un SU et l'utilisateur peut s'il a le
** password de root devenir calife a la place du calife.
**
** Dans tous les cas, un fichier log est maintenu a jour des differents
** usages du programme soit par syslog(3) soit directement.
**
** Le programme utilise maintenant les facilites du demon syslogd(8) pour
** afficher sur la console le succes ou l'echec du lancement d'un `...'.
**
** Si le programme est compile en mode paranoiaque (le defaut maintenant),
** il demande le mot de passe de l'utilisateur qui lance ... de facon a
** assurer une securite maximale.
**
** Le programme doit etre suid root pour fonctionner.
**
** Compilation: via le makefile
**
** Copyright (c) 1991-2010 by Ollivier ROBERT
** A distribuer selon les regles de la GNU GPL General Public Licence
** Voir le fichier COPYING fourni.
**
** 1.0 01/08/91 version pour Antenne 2, lance tcsh par defaut.
** 1.1 04/04/92 version pour Marne-L-V, utilise le shell de login du user
** en question.
** 1.2 27/05/92 permet de ... vers quelqu'un autre comme su(1)
** 1.3 16/06/92 utilise syslog(3) en plus du log
** 1.4 17/06/92 log le debut et la fin de chaque session via un fork et
** un wait.
** 1.5 18/06/92 ne change les droits effectifs (uid,gid) que pour le fils
** facon a ce que ... soit tjs au meme user.
** 1.6 19/06/92 * correction bug stupide : oubli de verifier si le
** user_to_be existe ... C'etait dans la 1.2 :-(
** * on permet a root de ... sur un user, comme su(1).
** 1.7 29/06/92 * Rajout mode paranoiaque : rentree du mot de passe de
** l'utilisateur pour authentification maximale.
** Compilation avec un -DPARANOID
** Seul root n'en a pas besoin.
** * Si le mode paranoiaque est selectionne, l'entree dans
** syslog sera calife+ et non pas calife tout court.
** * Si le user en question n'a pas de mot de passe,
** l'usage de calife est interdit pour des raisons
** evidentes :-)
** * Refonte interne, creation des deux fonctions
** OpenDatabases & VerifyPassword
** * Support pour changer le shell via le fichier
** d'autorisation, ne marche pas encore, a voir...
** 1.8 07/06/92 * Mode paranoiaque par defaut : -DRELAXED pour l'inhiber
** * Le changement de shell marche (sauf pour root a Marne ?
** Permission denied).
** * Mode debug (-DDEBUG) : plus verbeux, affiche les
** variables, etc.
** * Mode sans syslog (-DNO_SYSLOG) pour les machines avec
** un vieux syslog (SunOS 3.2) ou pas du tout. (SVR3 et
** autres derives).
** 1.9 08/06/92 * rajout de la liste des login sur lesquels un utilisateur
** a le droit d'executer calife.
** * Creation de la fonction VerifyAuthorizations qui va
** effectuer la lecture de la base d'auth.
** * Changement d'algo. pour la lecture de la base d'auth :
** plusieurs espaces/tabs, commentaires.
** * Support de SCO et SunOS 3.2 directement (non teste).
** * Plus de mode CUSTOM_SHELL, ca devient en fait le
** defaut, le code de gestion de liste de users n'etant
** pas compatible si le mode n'est pas CUSTOM_SHELL. (et
** ca ne vaut pas le coup de les reecrire :-))
** * nettoyage du code, ajout de commentaires.
** * Le probleme de l'execl de tcsh resiste encore, je ne
** sais pas d'ou ca vient...
** * Control de l'exit status du fils pour le pb ci-dessus.
** 2.0 13/09/92 * Abandon des listes d'utilisateurs, le programme revient
** a sa vocation originelle, c-a-d devenir root. De toute
** maniere, ca simplifie le code et root peut devenir qui il
** veut.
** * Le probleme de tcsh vient du fait qu'il a l'impression
** d'etre setuid. Un patch violent vient de sortir...
** #define NO_UGLY_QUIRK pour l'enlever :-)
** * Calife devient network-aware en utilisant
** les Yellow Pages (aka NIS) si elles sont presentes.
** la map utilisee a pour nom `calife_auth'. Le format est
** le meme que pour le fichier d'authorisations.
** * ATTENTION : le format de la base change pour utiliser les
** YP comme les maps standards : le separateur est `:'
** login_name:[custom_shell]
** * Ajout de string2passwd qui transforme une ligne de map
** passwd en une structure passwd.
** * Fix pour AIX 3.x qui ne semble pas avoir de macro
** WCOREDUMP pour wait(3)
** 2.1 23/03/93 * Changement des messages affiches de maniere a mimer ceux
** de su(1).
** * Changement du format des messages a syslog(3)
** * Modification du Makefile pour trouver su(1)
** Ajout variable SU_CMD
** * Utilisation de setprocmask a la place de signal pour
** les systems Posix
** * Portage Linux a l'aide de Rene Cougnenc : en fait juste
** une autre entree dans conf.h
** * Modification a l'appel de /bin/sh, on ajoute un exec.
** 2.2 03/09/93 * Refonte interne du code, simplification, changement
** des noms des fonctions pour etre consistent, renvoie de
** valeurs au lieu d'utiliser la variable globale allowed
** qui disparait.
** * Ajout de exec_shell pour simplification.
** * Correction petit bug si YP.
** 2.3 04/09/93 * Separation en trois fichiers sources : calife.c, db.c et
** util.c.
** * Reecriture du Makefile
** * Modification de conf.h pour les variables globales
** * Changement dans les logs : utilise syslog(3) _ou_ un
** fichier de log annexe, pas les deux.
** 2.4 07/01/94 * FreeBSD a la fonction initgroups(2)
** * FreeBSD 1.1 n'a pas besoin du hack violent pour tcsh
** * correction bug dans lequel wanted_user est ecrasee
** par l'appel a getpwname(calife).
** * FreeBSD 1.1 dispose des YP !!
** * Changement de _POSIX_SOURCE en POSIX_SIGNALS
** 2.5 22/04/94 * Incorporation de modifs pour SVR4 et sa p... de gestion
** des shadow passwords.
** * Securisation du programme en empechant les cores avec
** rlimit et la gestion des uid/euid/ssuid. Nouvelle option
** HAVE_RLIMIT.
** * Modification de la gestion de wait(2) : ajout du #define
** HAVE_INT_WAIT pour les systèmes ayant ``int status'' et
** non pas ``union wait status''.
** 2.6 25/09/94 * Ajout de l'execution d'un fichier .calife.out a la fin
** de la session s'il existe. Cette modification s'inscrit
** dans la gestion du serveur FrMug.
** * Changement de NO_UGLY_QUIRK en NOSETUID_SHELL (inverse)
** * Remplacement des seteuid(2) en setresuid(2) sur HP-UX.
** * Fin du support YP.
** * .calife.out devient global (plus intéressant). Le nom
** est spécifié dans le Makefile, le symbole étant
** CALIFE_OUT (par défaut /etc/calife.out)
** 2.7 23/04/95 * Rajout des listes d'utilisateurs -- pour un client
** mais peut être pratique.
** Le format est le suivant :
** login[:shell][:user1,user2,...,usern]
** * Elimination d'allocation statiques -> xalloc
** * Ajout des macros pour les messages de DEBUG, rend le
** code plus lisible.
** * Fixes divers (mem. leak, etc.) potentiellement ennuyeux.
** * Support de la version de crypt(3) utilisant MD5 sur
** FreeBSD 2.x.
** * Fixe un bug dans la recopie de user_to_be avec un '\0'
** à la fin. Signalé par Marc Baudoin.
** * utilisation de l'ancienne valeur de RLIMIT_CORE juste
** avant l'exec du shell.
** * Ajout d'un hack pour contourner un bug de SSH sur SunOS.
** Si getlogin(3) renvoie NULL, on regarde dans le fichier
** utmp.
** * Ajout des appels à die() aux points statégiques.
** * Réorganisation des commentaires, déplacement de code.
** 2.8 15/10/95 * Passage à GNU autoconf avec changement de divers
** symboles.
** * Support de "-" comme premier paramètre pour faire relire
** les fichiers d'init (.login,.profile)
** * Meilleur contrôle sur le fichier out_rc.
** * Correction bug si argv[1] == '-'.
** * Correction bug d'allocation mémoire, trouvé par
** Thomas Quinot.
** * Calife exige un tty associé à stdin, trouvé par
** Laurent Wacrenier.
** * Compilation sur Hurd + simplification des strcpy.
** Thomas Quinot.
** * Utilise utmp aussi sous Linux et amélioration du
** traitement.
** * Utilise un code analogue à su(8) pour pallier aux
** déficiences de getlogin(3).
** * Contourne un bug de getpass(3) sur Linux/glibc.
** * /etc/calife.out devient optionnel.
** * il est possible de spécifier un group dans calife.auth
** via @group:...
** * syslog(3) est maintenant requis.
** 3.0 04/05/05 * PAMification de calife, PAM est désormais *obligatoire*
** les gens ne l'ayant pas sont invités à rester à 2.8.
** * Le mode RELAXED sans mot de passe disparait.
**/
#define MAIN_MODULE
#ifndef lint
static const char * rcsid = "@(#) $Id: calife.c,v 7b2576d3600f 2017/08/08 11:00:39 roberto $";
#endif
#include "config.h" /* généré par configure */
/* fichier de configuration */
#include "conf.h"
int custom_shell= 0; /* modification du shell ? */
char * shell; /* nom du shell */
uid_t ssid; /* saved uid -- POSIX */
int want_login = 0; /* like 'su -' or not */
char * _group; /* if auth. through group */
#ifdef WITH_PAM
pam_handle_t *pamh = NULL;
#endif /* WITH_PAM */
#ifdef HAVE_RLIMIT
static struct rlimit rlp, orlp;
#endif
int
main (int argc, char * argv [])
{
int allowed = 0; /* l'utilisateur est-il valide ? */
char * name, * user_to_be, * tty, this_time [30];
#ifdef WANT_GLOBAL_RC
char * out_rc;
#endif
char * uargv;
uid_t uid;
time_t t;
struct passwd * test_user;
#ifdef HAVE_POSIX_SIGNALS
sigset_t old_set, sig_set;
#endif
#ifdef WITH_PAM
int e;
#endif
name = NULL;
tty = NULL;
ssid = geteuid (); /* get saved uid for swapping -- security reasons */
RELEASE_ROOT;
#ifndef DEBUG
if (ssid != 0) /* ... not setuid, exit */
exit (11);
#endif
/* displays compilation options */
#ifdef DEBUG
fprintf (stderr, "Calife : How to become someone else legally\n"
"Distribute in respect of the GNU General Public Licence\n"
"Copyright (c) 1991-2010 by Ollivier ROBERT\n");
fprintf (stderr, "Revision: %s\n", rcsid);
fprintf (stderr, "Options: ");
fprintf (stderr, "custom_shell, ");
#ifdef NO_SETUID_SHELL
fprintf (stderr, "no_setuid_shell, ");
#endif /* NO_SETUID_SHELL */
#ifdef WANT_GLOBAL_RC
fprintf(stderr, "global_rc, ");
#endif /* WANT_GLOBAL_RC */
#ifdef WITH_PAM
fprintf (stderr, "with_pam,");
#endif /* WITH_PAM */
fprintf (stderr, "su_like, ");
fprintf (stderr, "debug\n");
fflush (stderr);
#endif /* DEBUG */
#ifdef HAVE_RLIMIT
/*
* save the old limit values
*/
#ifndef DEBUG
getrlimit (RLIMIT_CORE, &orlp);
rlp.rlim_max = 0; /* no core file */
rlp.rlim_cur = 0;
setrlimit (RLIMIT_CORE, &rlp);
#endif /* !DEBUG */
#endif /* HAVE_RLIMIT */
#ifndef HAVE_POSIX_SIGNALS
/* no signals !! */
(void) signal (SIGQUIT, SIG_IGN);
(void) signal (SIGINT, SIG_IGN);
(void) signal (SIGHUP, SIG_IGN);
(void) signal (SIGABRT, SIG_IGN);
(void) signal (SIGTERM, SIG_IGN);
(void) signal (SIGCHLD, SIG_IGN);
#ifdef SIGTTOU
(void) signal (SIGTTOU, SIG_IGN);
#endif /* SIGTTOU */
#else /* HAVE_POSIX_SIGNALS */
sigemptyset (&sig_set);
sigaddset (&sig_set, SIGQUIT);
sigaddset (&sig_set, SIGINT);
sigaddset (&sig_set, SIGHUP);
sigaddset (&sig_set, SIGABRT);
sigaddset (&sig_set, SIGTERM);
sigaddset (&sig_set, SIGCHLD);
sigaddset (&sig_set, SIGTTOU);
sigprocmask (SIG_BLOCK, &sig_set, &old_set);
#endif
/*
* We insist on having a controlling terminal
*/
if (!isatty (0))
{
die (1, "No tty associated with stdin, bailing out");
}
user_to_be = (char *) xalloc (MAXLOGNAME + 1);
/*
* default is root
*/
(void) strcpy (user_to_be, ROOT_LOGIN);
/*
* check arguments
*/
uargv = argv[1]; /* points on username */
if (argc == 3 && !strcmp (uargv, "-"))
{
want_login = 1;
argc--;
uargv = argv[2]; /* skip first arg */
}
if (argc >= 3)
{
die (1, "Usage : %s [-] [user_name]\n", argv [0]);
/*NOTREACHED*/
}
if (argc == 2) /* un argument = user_to_be */
{
int n_len;
/*
* check whether the parameter is a "-" or not
*/
if (!strcmp (uargv, "-"))
want_login = 1;
else
{
/*
* verify length
*/
if ((n_len = strlen (uargv)) > MAXLOGNAME)
{
die (1, "Name too long `%s'", uargv);
/*NOTREACHED*/
}
/*
* avoid misuse and special characters
*/
{
int m;
m = strspn (uargv, ACCEPT_CHARS);
if (n_len != m)
{
die (1, "Illegal characters in username `%s'", uargv);
/*NOTREACHED*/
}
}
strncpy (user_to_be, uargv, n_len);
user_to_be [n_len] = '\0';
}
}
/*
* get tty name, for the log file
*/
{
char * p = ttyname (0);
if (p == NULL)
{
die (1, "No tty associated with stdin, bailing out");
/*NOTREACHED*/
}
tty = (char *) xalloc (strlen (p) - 4);
strcpy (tty, p + 5); /* strip /dev/ */
}
uid = getuid();
name = whoami();
/*
* open syslod log file
*/
#ifdef WITH_PAM
openlog ("calife/pam", LOG_PID | LOG_CONS, LOG_AUTH);
#else
openlog ("calife+", LOG_PID | LOG_CONS, LOG_AUTH);
#endif /* WITH_PAM */
/*
* does the user we want to become exist or not ?
*/
test_user = getpwnam (user_to_be);
if (test_user == NULL)
{
syslog (LOG_AUTH | LOG_ERR, "BAD CALIFE %s to unknown %s on %s", name, user_to_be, tty);
die (8, "Unknown user %s.\n", user_to_be);
/* NOT REACHED */
}
/*
* test if user already root
*/
if (uid == 0)
{
if (!strcmp (user_to_be, ROOT_LOGIN))
die (0, "Already root.");
}
/*
* open database and log file
*/
if (open_databases ()) /* successful opening ? */
allowed = 0;
else /* verify rights, even for root just for shell */
allowed = verify_auth_info (name, user_to_be);
/*
* record the time
*/
time (&t);
strcpy (this_time, ctime (&t));
this_time [24] = '\0'; /* strip \n */
if (allowed) /* hello, master-to-be */
{
#if defined(HAVE_SYS_WAIT_H)
int status;
#else /* !HAVE_SYS_WAIT_H */
union wait status;
#endif /* HAVE_SYS_WAIT_H */
struct passwd * calife, * wanted_user, * p_calife;
calife = (struct passwd *) xalloc (sizeof (struct passwd));
wanted_user = (struct passwd *) xalloc (sizeof (struct passwd));
authenticate_user (name, user_to_be, this_time, tty);
switch (fork ())
{
case -1:
/*
* fork error...
*/
die (5, "\nCalife: Fork failure: %s", strerror(errno));
/* NOT REACHED */
case 0:
/*
* child process, will become shell
*/
test_user = getpwnam (user_to_be);
memcpy (wanted_user, test_user, sizeof (struct passwd));
MESSAGE_4 ("uid,gid: %lu,%lu --> %u,%u\n", getuid(), \
getgid(), wanted_user->pw_uid, \
wanted_user->pw_gid);
#ifdef HAVE_POSIX_SIGNALS
sigprocmask (SIG_SETMASK, &old_set, NULL);
#endif
MESSAGE ("Looking for shell after changing rights...\n");
p_calife = getpwnam (name); /* return ptr is static */
if (p_calife == NULL)
die (1, "Bad pw data errno = %d", errno);
else
memcpy (calife, p_calife, sizeof (struct passwd));
#ifdef DEBUG
{
unsigned int e1, e2;
GET_ROOT;
#ifdef HAVE_INITGROUPS /* XXX don't know about linux */
initgroups (user_to_be, wanted_user->pw_gid);
#endif /* HAVE_INITGROUPS */
e2 = setgid (wanted_user->pw_gid);
e1 = setuid (wanted_user->pw_uid);
MESSAGE_5(" user=%s uid=%d gid=%d e1=%u e2=%u\n", \
user_to_be, wanted_user->pw_uid, wanted_user->pw_gid, \
e1, e2);
}
#else
GET_ROOT;
#ifdef HAVE_INITGROUPS /* XXX don't know about linux */
initgroups (user_to_be, wanted_user->pw_gid);
#endif /* HAVE_INITGROUPS */
(void) setgid (wanted_user->pw_gid);
(void) setuid (wanted_user->pw_uid);
#endif
if (!custom_shell)
{
exec_shell (calife->pw_shell);
}
else
{
exec_shell (shell);
}
/* NOT REACHED well should not :-) */
fprintf (stderr, "shell = >>%s<<\n", "/bin/sh");
execl ("/bin/sh", "sh", NULL);
die (2, "\nAARRRGGGHHH, exec (shell) failed... errno = %d",
errno);
default:
{
#ifdef WANT_GLOBAL_RC
int fd;
#endif /* WANT_GLOBAL_RC */
/*
* father, will wait for the child
*/
/*
* cleanup
*/
free (calife);
free (wanted_user);
#ifdef WITH_PAM
if (pamh)
{
if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS)
{
syslog (LOG_AUTH | LOG_ERR, "pam_open_session: %s",
pam_strerror (pamh, e));
}
else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) !=
PAM_SUCCESS)
{
syslog (LOG_AUTH | LOG_ERR, "pam_setcred: %s",
pam_strerror (pamh, e));
}
}
#endif /* WITH_PAM */
if (allowed == 2)
syslog (LOG_AUTH | LOG_NOTICE, "%s@%s to %s on %s - BEGIN",
name, _group, user_to_be, tty);
else
syslog (LOG_AUTH | LOG_NOTICE, "%s to %s on %s - BEGIN", name, user_to_be, tty);
wait (&status);
RELEASE_ROOT;
#ifdef WANT_GLOBAL_RC
out_rc = (char *) xalloc (strlen (CALIFE_OUT_FILE) + 1);
strcpy (out_rc, CALIFE_OUT_FILE);
MESSAGE_1 ("Looking for %s.\n", out_rc);
fd = open (out_rc, O_RDONLY);
if (fd != EOF)
{
int err;
struct stat sb1, sb2;
/*
* Get some info
*/
err = fstat (fd, &sb1);
if (err)
{
syslog (LOG_AUTH | LOG_NOTICE, "fstat: %s unreadable/executable", out_rc);
goto done;
}
/*
* See if symlink
*/
err = lstat (out_rc, &sb2);
if (err)
{
syslog (LOG_AUTH | LOG_NOTICE, "lstat: %s unreadable/executable", out_rc);
goto done;
}
/*
* Verify no-one tried to change it on the fly
*/
if (sb1.st_dev != sb2.st_dev ||
sb1.st_ino != sb2.st_ino)
{
syslog (LOG_AUTH | LOG_NOTICE, "lstat: %s IS A SYMLINK !!", out_rc);
goto done;
}
/*
* Verify that it is not rwxrwxrwx
*/
if ((sb1.st_mode & S_IRWXO) == S_IRWXO)
{
syslog (LOG_AUTH | LOG_NOTICE, "fstat: %s IS WORLD WRITABLE !!", out_rc);
goto done;
}
/*
* See if at least "something/something/r-x"
*/
if (((sb1.st_mode & S_IXOTH) == S_IXOTH) &&
((sb1.st_mode & S_IXOTH) == S_IXOTH))
{
#if defined(HAVE_SYS_WAIT_H)
int status1;
#else /* !HAVE_SYS_WAIT_H */
union wait status1;
#endif /* HAVE_SYS_WAIT_H */
pid_t pid;
close (fd);
MESSAGE_1 ("%s found, executing it.\n", out_rc);
pid = fork();
if (pid == -1)
{
die (5, "\nFork failure. exiting ...");
}
else if (pid) /* father */
{
wait (&status1);
}
else /* child */
{
/*
* Potential race condition: someone could have
* changed out_rc. Could be fixed by using the
* /dev/fd/N trick but it is not universal...
*
* We could dup fd into stdin and launch /bin/sh on
* that too...
*
* We're not root anymore so it is less important
*/
execl ("/bin/sh", "sh", "-c", out_rc, NULL);
die (1, "Error reading %s", out_rc);
}
}
else
fprintf (stderr, "\a%s not executable/readable.\n", out_rc);
}
done:
free (out_rc);
#endif /* WANT_GLOBAL_RC */
if (allowed == 2)
syslog (LOG_AUTH | LOG_NOTICE, "%s@%s to %s on %s - END.",
name, _group, user_to_be, tty);
else
syslog (LOG_AUTH | LOG_NOTICE, "%s to %s on %s - END.", name, user_to_be, tty);
/*
* cleanup
*/
#ifdef WITH_PAM
if (pamh)
{
if ((e = pam_setcred (pamh, PAM_DELETE_CRED)) != \
PAM_SUCCESS)
syslog (LOG_AUTH | LOG_ERR, "pam_setcred: %s",\
pam_strerror(pamh, e));
if ((e = pam_close_session (pamh, 0)) != PAM_SUCCESS)
syslog(LOG_AUTH | LOG_ERR, "pam_close_session: %s",\
pam_strerror(pamh, e));
if ((e = pam_end (pamh, e)) != PAM_SUCCESS)
syslog(LOG_AUTH | LOG_ERR, "pam_end: %s",\
pam_strerror(pamh, e));
pamh = NULL;
}
#endif
closelog ();
#ifdef DEBUG
if (WIFEXITED (status))
{
if (WEXITSTATUS (status))
fprintf (stderr, "Child died with error level of %d, check please.\n", WEXITSTATUS (status));
}
else
{
if (WIFSIGNALED (status))
fprintf (stderr, "Child was killed by signal %d\n", WTERMSIG (status));
#if !defined(AIX3) && !defined(HAVE_SYS_WAIT_H)
#ifndef _POSIX_SOURCE
if (WCOREDUMP (status))
fprintf (stderr, "And there is a core to look upon...");
#endif /* !_POSIX_SOURCE */
#endif /* !AIX3 */
}
#endif /* DEBUG */
}
break;
}
}
else
{
/*
* su will ask for the password, if any
*/
syslog (LOG_AUTH | LOG_ERR, "BAD CALIFE %s to %s on %s",
name, user_to_be, tty);
closelog ();
fprintf (stderr, "Calife failed. Sorry, trying to run su.\n");
fflush (stderr);
/*
* give the baby to su
*/
execl (SU_CMD, "su", user_to_be, NULL);
die (3, "\nBy Zandru's Nineth Hell !!! Even su failed...");
/* NOT REACHED */
}
return 0;
}
/** Trouve et execute le shell passe en parametre
**
** Parametres : shell char * shell a executer
**
** Retourne : n'est pas sense revenir...
**
** Privileges : aucun
**/
void
exec_shell (char * shell_name)
{
int fd, err;
char * shell_arg0;
struct stat sb;
MESSAGE_2 ("standard_shell = |%100s| basename = |%100s|\n",
shell_name, basename (shell_name));
fd = open (shell_name, O_RDONLY);
if (fd == -1)
die (3, "Shell not executable/not found\n");
err = fstat (fd, &sb);
if (err)
die (3, "Can't fstat()\n");
close (fd);
/*
* If we can execute it, do it
*/
if (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))
{
#ifdef HAVE_RLIMIT
setrlimit (RLIMIT_CORE, &orlp); /* restore old limit */
#endif /* HAVE_RLIMIT */
#ifdef NO_SETUID_SHELL
char * cmdline = (char *) xalloc (MAX_STRING);
snprintf (cmdline, "exec %100s", shell_name);
if (!strcmp (basename (shell_name), "tcsh"))
{
execl ("/bin/sh", "sh", "-c", cmdline, 0);
fprintf (stderr, "\nexecl (/bin/sh -c %s) failed... errno = %d\n", shell_name, errno);
fflush (stderr);
}
#else /* !NO_SETUID_SHELL */
/*
* Well-known convention
*/
if (want_login)
{
char * pt;
pt = basename (shell_name);
shell_arg0 = (char *) xalloc (strlen (pt) + sizeof (char));
strncpy (shell_arg0, pt, strlen (pt) + sizeof (char));
*shell_arg0 = '-';
}
else
shell_arg0 = basename (shell_name);
#ifdef DEBUG
MESSAGE_2 (" shell_name=%s shell_arg0=%s\n", shell_name, shell_arg0);
#endif /* DEBUG */
execl (shell_name, shell_arg0, NULL);
fprintf (stderr, "\nexecl (%s) failed... errno = %d\n", shell_name, errno);
fflush (stderr);
#endif /* NO_SETUID_SHELL */
}
#ifdef DEBUG
else
{
MESSAGE_1 ("No access to this shell = %s\n", shell_name);
}
#endif /* DEBUG */
}
/** Renvoie le nom de l'utilisateur courant
**
** Parameters : aucun
**
** Retourne : name char * login
**
** Privileges : aucun
**/
char *
whoami (void)
{
char * login, * name;
struct passwd *pwd;
uid_t uid;
/*
* Get login name the standard way
*
* Code extracted from usr.bin/su/su.c
* heavily modified.
*/
uid = getuid();
login = getlogin();
if (login == NULL)
{
pwd = getpwuid(uid);
MESSAGE_2 ("getpwuid uid = %ld login = %s\n", uid, pwd->pw_name);
}
else
{
pwd = getpwnam(login);
MESSAGE_1 ("getlogin = %s\n", login);
}
if (pwd == NULL)
{
die (1, "who are you?");
/*NOTREACHED*/
}
else
login = pwd->pw_name;
MESSAGE_2 ("uid = %ld name = %s\n", uid, login);
if (login == NULL || *login == '\0')
{
/*
* Under SunOS, ssh sometimes makes getlogin(3) think the utmp
* entry is invalid thus getlogin(3) returns NULL.
* We'll look in utmp ourselves.
*/
#if defined(SUNOS4) || defined(__linux__)
int utmp_fd, get_out = 0, err = 0;
struct utmp utmp;
#ifdef DEBUG
fprintf (stderr, "getlogin failed, reading utmp\n");
fflush (stderr);
#endif /* DEBUG */
utmp_fd = open (_PATH_UTMP, O_RDONLY);
if (utmp_fd == -1)
get_out = 1;
else
{
/*
* read each entry
*/
do
{
err = read (utmp_fd, &utmp, sizeof utmp);
if (err == -1 || err == 0)
{
get_out = 1;
break;
}
} while (strcmp (tty, utmp.ut_line));
}
close (utmp_fd);
/*
* XXX
* assuming 8 chars is unwise but there is no other way under SunOS
* XXX
*/
{
#ifdef UT_NAMESIZE
int max_size = UT_NAMESIZE;
#else /* !UT_NAMESIZE */
int max_size = 8;
#endif /* UT_NAMESIZE */
int l_name = 0;
name = (char *) xalloc ((max_size + 1) * sizeof (char));
strncpy (name, utmp.ut_name, sizeof utmp.ut_name);
while (name [l_name] && l_name != max_size)
l_name++;
name [l_name] = '\0';
}
if (get_out)
{
#endif /* !SUNOS4 && !__linux__ */
die (1, "You don't exist, get out.");
#if defined (SUNOS4) || defined (__linux__)
}
#endif /* SUNOS4 && __linux__ */
}
else
{
/*
* don't assume length
*/
int l_len = strlen (login);
name = (char *) xalloc ((l_len + 1) * sizeof (char));
strncpy (name, login, l_len);
name [l_len] = '\0';
}
return(name);
}