unix_user.c 27.1 KB
Newer Older
1
2
3
4
5
6
7
/* unix_user.c
 *
 * User-related functions on UN*X
 *
 * $Id$
 */

Niels Möller's avatar
Niels Möller committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 2000 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

27
28
29
#include "server_userauth.h"

#include "format.h"
30
#include "io.h"
31
#include "read_file.h"
32
#include "reaper.h"
Niels Möller's avatar
Niels Möller committed
33
#include "server_pty.h"
34
35
36
37
38
39
#include "werror.h"
#include "xalloc.h"

#include <assert.h>
#include <errno.h>
#include <string.h>
40
#include <time.h>
41

42
#include <sys/types.h>
43
#include <sys/stat.h>
44
45
#include <fcntl.h>

46
#if HAVE_UNISTD_H
47
#include <unistd.h>
48
#endif
49

50
51
#include <sys/wait.h>

52
#include <signal.h>
53
54
55
56
57
58
59
60
61
62
63

#if HAVE_CRYPT_H
# include <crypt.h>
#endif
#include <pwd.h>
#include <grp.h>

#if HAVE_SHADOW_H
#include <shadow.h>
#endif

64
#if WITH_UTMP
65
66
67
# if HAVE_UTMP_H
#  include <utmp.h>
# endif
68

69
70
71
72
# if HAVE_UTMPX_H
#  include <utmpx.h>
# endif
#else /* !WITH_UTMP */
73
  struct utmp;
74
75
#endif

76
77
78
79
#if HAVE_LIBUTIL_H
# include <libutil.h>
#endif

80
81
82
/* Forward declaration */
struct unix_user_db;

83
84
85
86
87
#include "unix_user.c.x"

/* GABA:
   (class
     (name unix_user)
88
     (super lsh_user)
89
     (vars
Niels Möller's avatar
Niels Möller committed
90
       (gid . gid_t)
91
92
93

       ; Context needed for some methods.
       (ctx object unix_user_db)
94
       
95
96
97
98
99
100
101
102
       ; These strings include a terminating NUL-character, for 
       ; compatibility with library and system calls. This applies also
       ; to the inherited name attribute.

       (passwd string)  ; Crypted passwd
       (home string)
       (shell string))) */

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* GABA:
   (class
     (name pwhelper_callback)
     (super exit_callback)
     (vars
       (user object unix_user)
       (c object command_continuation)
       (e object exception_handler)))
*/

static void
do_pwhelper_callback(struct exit_callback *s,
		     int signaled, int core UNUSED, int value)
{
  CAST(pwhelper_callback, self, s);
118

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  if (signaled || value)
    {
      static const struct exception invalid_password
	= STATIC_EXCEPTION(EXC_USERAUTH, "Invalid password according to helper program.");
      EXCEPTION_RAISE(self->e, &invalid_password);
    }
  else
    COMMAND_RETURN(self->c, self->user);
}

static struct exit_callback *
make_pwhelper_callback(struct unix_user *user,
		       struct command_continuation *c,
		       struct exception_handler *e)
{
  NEW(pwhelper_callback, self);
  self->super.exit = do_pwhelper_callback;
  self->user = user;
  self->c = c;
  self->e = e;

  return &self->super;
}

/* NOTE: Consumes the pw string if successful. */
144
static int
145
146
147
kerberos_check_pw(struct unix_user *user, struct lsh_string *pw,
		  struct command_continuation *c,
		  struct exception_handler *e)
148
149
{
  /* Because kerberos is big and complex, we fork a separate process
150
   * to do the work. */
151
152
153

  int in[2];
  pid_t child;
154
155
156
157
158

  /* First look if the helper program seems to exist. */
  if (access(user->ctx->pw_helper, X_OK) < 0)
    {
      /* No help available */
159
160
      werror("Password helper program '%z' not available %e\n",
	     user->ctx->pw_helper, errno);
161
162
      return 0;
    }
163
164
165
166
167
168
169
170
171
172
173
174
  
  if (!lsh_make_pipe(in))
    {
      werror("kerberos_check_pw: Failed to create pipe.\n");
      return 0;
    }
  
  child = fork();
  
  switch (child)
    {
    case -1:
175
      werror("kerberos_check_pw: fork failed %e\n", errno);
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
      return 0;

    case 0:
      {  /* Child */
	int null_fd;
      
	null_fd = open("/dev/null", O_RDWR);
	if (null_fd < 0)
	  {
	    werror("kerberos_check_pw: Failed to open /dev/null.\n");
	    _exit(EXIT_FAILURE);
	  }
	if (dup2(in[0], STDIN_FILENO) < 0)
	  {
	    werror("kerberos_check_pw: Can't dup stdin!\n");
	    _exit(EXIT_FAILURE);
	  }

	if (dup2(null_fd, STDOUT_FILENO) < 0)
	  {
	    werror("kerberos_check_pw: Can't dup stdout!\n");
	    _exit(EXIT_FAILURE);
	  }

	if (dup2(null_fd, STDERR_FILENO) < 0)
	  {
	    _exit(EXIT_FAILURE);
	  }
      
	close(in[1]);
	close(null_fd);

208
	execl(user->ctx->pw_helper, user->ctx->pw_helper, user->super.name->data, NULL);
209
210
211
212
213
	_exit(EXIT_FAILURE);
      }
    default:
      {
	/* Parent */
214
	struct lsh_fd *fd;
215

216
	close(in[0]);
217

218
	fd = io_write(make_lsh_fd(in[1], "password helper stdin",
219
				  e),
220
		      pw->length, NULL);
221

222
	A_WRITE(&fd->write_buffer->super, pw);
223

224
	REAP(user->ctx->reaper, child, make_pwhelper_callback(user, c, e));
225

226
	return 1;
227
228
229
230
      }
    }
}

231
232
233
234
235
/* FIXME: This could be generalized to support some kind of list of
 * password databases. The current code first checks for unix
 * passwords, and if that fails, it optionally invokes a helper
 * program to verify the password, typically used for kerberos. */
static void
236
do_verify_password(struct lsh_user *s,
237
		   struct lsh_string *password,
238
239
		   struct command_continuation *c,
		   struct exception_handler *e)
240
241
{
  CAST(unix_user, user, s);
242
243
  const struct exception *x = NULL;

244
245
  /* No supported password verification methods allows passwords
   * containing NUL, so check that here. */
246

247
  if (!lsh_get_cstring(password))
248
    {
249
250
      static const struct exception invalid_passwd
	= STATIC_EXCEPTION(EXC_USERAUTH, "NUL character in password.");
251

252
253
254
255
      EXCEPTION_RAISE(e, &invalid_passwd);
      return;
    }
  
256
257
258
  /* NOTE: Check for accounts with empty passwords, or generally short
   * passwd fields like "NP" or "x". */
  if (!user->passwd || (user->passwd->length < 5) )
259
    {
260
261
      static const struct exception no_passwd
	= STATIC_EXCEPTION(EXC_USERAUTH, "No password in passwd db.");
262

263
264
265
266
267
      x = &no_passwd;

      /* NOTE: We attempt using kerberos passwords even if the
       * passwd entry is totally bogus. */
      goto try_helper;
268
269
    }

270
271
272
  /* Try password authentication against the ordinary unix database. */
  {
    char *salt = user->passwd->data;
273

274
    /* NOTE: crypt uses the *ugly* convention of returning pointers
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
     * to static buffers. */

    if (strcmp(crypt(password->data, salt), user->passwd->data))
      {
	/* Passwd doesn't match */
	static const struct exception invalid_passwd
	  = STATIC_EXCEPTION(EXC_USERAUTH, "Incorrect password.");
	
	x = &invalid_passwd;

	goto try_helper;
      }
    /* Unix style password authentication succeded. */
    lsh_string_free(password);
    COMMAND_RETURN(c, user);
    return;
  }
292
  
293
 try_helper:
294

295
296
297
298
299
300
301
302
303
  /* We get here if checks against the ordinary passwd database failed. */
  assert(x);
  
  if (user->ctx->pw_helper && kerberos_check_pw(user, password, c, e))
    /* The helper program takes responsibility for password
     * verification, and it also consumed the password string so that
     * we don't need to free it here. */
    ;
  else
304
305
    {
      lsh_string_free(password);
306
      EXCEPTION_RAISE(e, x);
307
308
309
310
311
312
    }
}

/* NOTE: No arbitrary file names are passed to this function, so we don't have
 * to check for things like "../../some/secret/file" */
static int
313
do_file_exists(struct lsh_user *u,
314
315
316
317
318
319
	       struct lsh_string *name,
	       int free)
{
  CAST(unix_user, user, u);
  struct lsh_string *path;
  struct stat st;
320
  const char *s;
321
322
  
  if (!user->home)
323
324
325
326
327
    {
      if (free)
	lsh_string_free(name);
      return 0;
    }
328
  
329
330
331
332
333
  path = ssh_format(free ? "%lS/%lfS" : "%lS/%lS",
		    user->home, name);
  s = lsh_get_cstring(path);
  
  if (s && (stat(s, &st) == 0))
334
335
336
337
338
339
340
341
    {
      lsh_string_free(path);
      return 1;
    }
  lsh_string_free(path);
  return 0;
}

342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
static const struct exception *
check_user_permissions(struct stat *sbuf, const char *fname,
		       uid_t uid, int secret)
{
  mode_t bad = secret ? (S_IRWXG | S_IRWXO) : (S_IWGRP | S_IWOTH);

  if (!S_ISREG(sbuf->st_mode))
    {
      werror("io.c: %z is not a regular file.\n",
	     fname);
      return make_io_exception(EXC_IO_OPEN_READ, NULL, 0, "Not a regular file");
    }
  if (sbuf->st_uid != uid)
    {
      werror("io.c: %z not owned by the right user (%i)\n",
	     fname, uid);
      return make_io_exception(EXC_IO_OPEN_READ, NULL, 0, "Bad owner");
    }

  if (sbuf->st_mode & bad)
    {
      werror("io.c: Permissions on %z too loose.\n",
	     fname);
      return make_io_exception(EXC_IO_OPEN_READ, NULL, 0, "Bad permissions");
    }

  return NULL;
}

371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
/* GABA:
   (class
     (name exc_read_user_file_handler)
     (super exception_handler)
     (vars
       (c object abstract_write))))
*/

static void
do_exc_read_user_file_handler(struct exception_handler *s,
			       const struct exception *e)
{
  CAST(exc_read_user_file_handler, self, s);

  verbose("reading user file failed: %z\n", e->msg);
  
  switch (e->type)
    {
    case EXC_IO_READ:
      A_WRITE(self->c, NULL);
      break;
    default:
      werror("reading user file failed: %z\n", e->msg);
      EXCEPTION_RAISE(self->super.parent, e);
    }
}

static struct exception_handler *
make_exc_read_user_file_handler(struct abstract_write *c,
				struct exception_handler *parent,
				const char *context)
{
  NEW(exc_read_user_file_handler, self);

  self->super.parent = parent;
  self->super.raise = do_exc_read_user_file_handler;
  self->super.context = context;
  
  self->c = c;

  return &self->super;
}

#define USER_FILE_BUFFER_SIZE 1000

416
/* NOTE: No arbitrary file names are passed to this method, so we
417
418
 * don't have to check for things like "../../some/secret/file",
 * or for filenames containing NUL. */
419

420
static const struct exception *
421
422
do_read_file(struct lsh_user *u, 
	     const char *name, int secret,
423
424
	     UINT32 limit,
	     struct abstract_write *c)
425
426
427
{
  CAST(unix_user, user, u);
  struct lsh_string *f;
428
  struct stat sbuf;
429
  const struct exception *x;
430
431
432
433
434

  pid_t child;
  /* out[0] for reading, out[1] for writing */
  int out[2];

435
  uid_t me = geteuid();
436
437
438
439
440

  /* There's no point trying to read other user's files unless we're
   * root. */

  if (me && (me != user->super.uid) )
441
442
    return make_io_exception(EXC_IO_OPEN_READ, NULL, 0, "Access denied.");
  
443
  if (!user->home)
444
445
    return make_io_exception(EXC_IO_OPEN_READ, NULL,
			     ENOENT, "No home directory");
446

447
  f = ssh_format("%lS/.lsh/%lz", user->home, name);
448
  
449
  if (stat(lsh_get_cstring(f), &sbuf) < 0)
450
451
    {
      if (errno != ENOENT)
452
	werror("io_read_user_file: Failed to stat %S %e\n", f, errno);
453
 
454
      lsh_string_free(f);
455
456

      return make_io_exception(EXC_IO_OPEN_READ, NULL, errno, NULL);
457
458
459
460
461
    }

  /* Perform a preliminary permissions check before forking, as errors
   * detected by the child process are not reported as accurately. */

462
  x = check_user_permissions(&sbuf, lsh_get_cstring(f), user->super.uid, secret);
463
464
465
  if (x)
    {
      lsh_string_free(f);
466
      return x;
467
468
469
470
471
    }
  
  if (!lsh_make_pipe(out))
    {
      lsh_string_free(f);
472
      return make_io_exception(EXC_IO_OPEN_READ, NULL, errno, NULL);
473
474
475
476
477
478
479
480
481
482
483
    }
  
  child = fork();

  switch (child)
    {
    case -1:
      /* Error */

      close(out[0]); close(out[1]);
      lsh_string_free(f);
484
      return make_io_exception(EXC_IO_OPEN_READ, NULL, errno, NULL);
485
486
487
488
489
      
    default:
      /* Parent */
      close(out[1]);

490
491
      lsh_string_free(f);

492
      /* NOTE: We could install an exit handler for the child process,
493
       * but there's nothing useful for that to do. */
494
495
496
497
498
499
500
501
502
503
      io_read(make_lsh_fd
	        (out[0], "stdout, reading a user file",
		 make_exc_read_user_file_handler(c,
						 &default_exception_handler,
						 HANDLER_CONTEXT)),
	      make_buffered_read(USER_FILE_BUFFER_SIZE,
				 make_read_file(c, limit)),
	      NULL);

      return NULL;
504
505
506
507
508
509

    case 0:
      /* Child */
      {
	int fd;
	close(out[0]);
510

511
	if ( (me != user->super.uid) && (seteuid(user->super.uid) < 0) )
512
	  {
513
	    werror("unix_user.c: do_read_file: setuid failed %e\n", errno);
514
515
	    _exit(EXIT_FAILURE);
	  }
516
	assert(user->super.uid == geteuid());
517
	
518
	fd = open(lsh_get_cstring(f), O_RDONLY);
519
520
521
522
523
524

	/* Check permissions again, in case the file or some symlinks
	 * changed under our feet. */

	if (fstat(fd, &sbuf) < 0)
	  {
525
	    werror("unix_user.c: do_read_file: fstat failed %e\n", errno);
526
527
528
	    _exit(EXIT_FAILURE);
	  }

529
530
	x = check_user_permissions(&sbuf, lsh_get_cstring(f),
				   user->super.uid, secret);
531
532
533

	if (x)
	  {
534
	    werror("unix_user.c: do_read_file: %z\n", x->msg);
535
536
	    _exit(EXIT_FAILURE);
	  }
537
538
539
540
541

	if (lsh_copy_file(fd, out[1]))
	  _exit(EXIT_SUCCESS);
	else
	  _exit(EXIT_FAILURE);
542
543
      }
    }
544
545
}

546
547
#define USE_LOGIN_DASH_CONVENTION 1

548
static const char *
549
550
format_env_pair(const char *name, struct lsh_string *value)
{
551
552
  assert(lsh_get_cstring(value));
  return lsh_get_cstring(ssh_format("%lz=%lS", name, value));
553
554
}

555
static const char *
556
557
format_env_pair_c(const char *name, const char *value)
{
558
  return lsh_get_cstring(ssh_format("%lz=%lz", name, value));
559
560
}

Niels Möller's avatar
Niels Möller committed
561
562
563
564
565
566
static int
chdir_home(struct unix_user *user)
{
  if (user->home)
    {
      if (chdir(lsh_get_cstring(user->home)) < 0)
567
	werror("chdir to home directory `%S' failed %e\n", user->home, errno);
Niels Möller's avatar
Niels Möller committed
568
569
570
571
572
      else
	return 1;
    }
  if (chdir("/") < 0)
    {
573
      werror("chdir to `/' failed %e\n", errno);
Niels Möller's avatar
Niels Möller committed
574
575
576
577
578
579
580
581
582
583
584
585
586
      return 0;
    }
  else
    return 1;
}

static void
exec_shell(struct unix_user *user, struct spawn_info *info)
{
  const char **envp;
  const char **argv;
  const char **shell_argv;
  const char *argv0;
587

Niels Möller's avatar
Niels Möller committed
588
589
  char *tz = getenv("TZ");
  unsigned i, j;
590
591

  trace("unix_user: exec_shell\n");
Niels Möller's avatar
Niels Möller committed
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  assert(user->shell);

  /* Make up an initial environment */
  debug("exec_shell: Setting up environment.\n");
  
  /* We need place for the caller's values, 
   *
   * SHELL, HOME, USER, LOGNAME, TZ, PATH
   *
   * and a terminating NULL */

#define MAX_ENV 6

  envp = alloca(sizeof(char *) * (info->env_length + MAX_ENV + 1));

  i = 0;
  envp[i++] = format_env_pair("SHELL", user->shell);

  if (user->home)
    envp[i++] = format_env_pair("HOME", user->home);

  /* FIXME: The value of $PATH should not be hard-coded */
  envp[i++] = "PATH=/bin:/usr/bin";
  envp[i++] = format_env_pair("USER", user->super.name);
  envp[i++] = format_env_pair("LOGNAME", user->super.name);

  if (tz)
    envp[i++] = format_env_pair_c("TZ", tz);

  assert(i <= MAX_ENV);
#undef MAX_ENV

  for (j = 0; j < info->env_length; j++)
    envp[i++] = format_env_pair(info->env[j].name, info->env[j].value);

  envp[i] = NULL;

  debug("exec_shell: Environment:\n");
  for (i=0; envp[i]; i++)
    debug("    '%z'\n", envp[i]);

#if USE_LOGIN_DASH_CONVENTION
634
  if (info->login)
Niels Möller's avatar
Niels Möller committed
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
    {
      /* Fixup argv[0], so that it starts with a dash */
      const char *p;
      char *s;
      const char *shell = lsh_get_cstring(user->shell);
        
      debug("do_exec_shell: fixing up name of shell...\n");
      
      s = alloca(user->shell->length + 2);

      /* Make sure that the shell's name begins with a -. */
      p = strrchr (shell, '/');
      if (!p)
	p = shell;
      else
	p ++;

      s[0] = '-';
      strncpy (s + 1, p, user->shell->length);
      argv0 = s;
    }
  else
#endif /* USE_LOGIN_DASH_CONVENTION */
    argv0 = lsh_get_cstring(user->shell);

  debug("exec_shell: argv0 = '%z'.\n", argv0);

  /* Build argument list for lsh-execuv. We need place for
   *
664
   * lsh-execuv -u uid -g gid -n name -i -- $SHELL argv0 <user args> NULL
Niels Möller's avatar
Niels Möller committed
665
   */
666
667
#define MAX_ARG 11
#define NUMBER(x) lsh_get_cstring(ssh_format("%di", (x)))
Niels Möller's avatar
Niels Möller committed
668
669
670
671
672
  
  argv = alloca(sizeof(char *) * (MAX_ARG + info->argc + 1));
  i = 0;
  argv[i++] = "lsh-execuv";
  argv[i++] = "-u";
673
  trace("exec_shell: After -u\n");
Niels Möller's avatar
Niels Möller committed
674
675
  argv[i++] = NUMBER(user->super.uid);
  argv[i++] = "-g";
676
  trace("exec_shell: After -g\n");
Niels Möller's avatar
Niels Möller committed
677
678
679
680
  argv[i++] = NUMBER(user->gid);
  argv[i++] = "-n";
  argv[i++] = lsh_get_cstring(user->super.name);
  argv[i++] = "-i";
681
  trace("exec_shell: After -i\n");
Niels Möller's avatar
Niels Möller committed
682
  argv[i++] = "--";
683
  argv[i++] = lsh_get_cstring(user->shell);
Niels Möller's avatar
Niels Möller committed
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
  shell_argv = argv + i;
  
  argv[i++] = argv0;

  assert(i <= MAX_ARG);
#undef MAX_ARG
#undef NUMBER
  for (j = 0; j<info->argc; j++)
    argv[i++] = info->argv[j];
  argv[i++] = NULL;
  
  debug("exec_shell: Argument list:\n");
  for (i=0; argv[i]; i++)
    debug("    '%z'\n", argv[i]);

  /* NOTE: The execve prototype uses char * const argv, and similarly
   * for envp, which seems broken. */
  
702
703
  trace("exec_shell: before exec\n");

Niels Möller's avatar
Niels Möller committed
704
705
706
707
708
709
  /* Use lsh-execuv only if we need to change our uid. */
  if (user->super.uid == getuid())
    execve(lsh_get_cstring(user->shell), (char **) shell_argv, (char **) envp);
  else
    execve(PREFIX "/sbin/lsh-execuv", (char **) argv, (char **) envp);

710
  werror("unix_user: exec failed %e\n", errno);
Niels Möller's avatar
Niels Möller committed
711
712
713
  _exit(EXIT_FAILURE);
}

714
715
716
717
static void
safe_close(int fd)
{
  if (fd != -1 && close(fd) < 0)
718
    werror("close failed %e\n", errno);
719
720
}

Niels Möller's avatar
Niels Möller committed
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
static struct lsh_process *
do_spawn(struct lsh_user *u,
	 struct spawn_info *info,
	 struct exit_callback *c)
{
  CAST(unix_user, user, u);
  /* Pipe used for syncronization. */
  int sync[2];
  pid_t child;

  if (!lsh_make_pipe(sync))
    {
      werror("do_spawn: Failed to create syncronization pipe.\n");
      return NULL;
    }
  
  child = fork();
  if (child < 0)
    {
740
      werror("unix_user: do_spawn: fork failed %e\n", errno);
741
      safe_close(sync[0]); safe_close(sync[1]);
742

743
744
      safe_close(info->in[0]);  safe_close(info->in[1]);
      safe_close(info->out[0]); safe_close(info->out[1]);
745
746
747
748
749
      safe_close(info->err[0]);
      /* Allow the client's stdout and stderr to be the same fd, e.g.
       * both /dev/null. */
      if (info->err[1] != info->out[1])
	safe_close(info->err[1]);
750

Niels Möller's avatar
Niels Möller committed
751
752
753
754
755
756
757
758
759
      return NULL;
    }
  else if (child)
    {
      /* Parent */
      struct lsh_process *process;
      char dummy;
      int res;
      
760
761
      trace("do_spawn: parent process\n");

762
763
764
      /* Close the child's fd:s, except ones that are -1 */
      safe_close(info->in[0]);
      safe_close(info->out[1]);
765
766
767
768
769

      /* Allow the client's stdout and stderr to be the same fd, e.g.
       * both /dev/null. */
      if (info->err[1] != info->out[1])
	safe_close(info->err[1]);
Niels Möller's avatar
Niels Möller committed
770

771
      safe_close(sync[1]);
Niels Möller's avatar
Niels Möller committed
772
773
774
775
776
777
778

      /* On Solaris, reading the master side of the pty before the
       * child has opened the slave side of it results in EINVAL. We
       * can't have that, so we'll wait until the child has opened the
       * tty, after which it should close its end of the
       * syncronization pipe, and our read will return 0.
       *
Niels Möller's avatar
Niels Möller committed
779
       * We need the syncronization only if we're actually using a
Niels Möller's avatar
Niels Möller committed
780
781
782
783
784
785
       * pty, but for simplicity, we do it every time. */
      
      do
	res = read(sync[0], &dummy, 1);
      while (res < 0 && errno == EINTR);

786
      safe_close(sync[0]);
787
788

      trace("do_spawn: parent after sync\n");
Niels Möller's avatar
Niels Möller committed
789
      
790
      process = unix_process_setup(child, &user->super, &c,
791
792
793
794
795
				   info->peer,
				   info->pty ? info->pty->tty_name : NULL);

      trace("do_spawn: parent after process setup\n");

Niels Möller's avatar
Niels Möller committed
796
797
798
799
800
801
      REAP(user->ctx->reaper, child, c);
      return process;
    }
  else
    { /* Child */
      int tty = -1;
802
803

      trace("do_spawn: child process\n");
Niels Möller's avatar
Niels Möller committed
804
805
      if (!chdir_home(user))
	_exit(EXIT_FAILURE);
806
      
807
      trace("do_spawn: child after chdir\n");
808
809
810
811
812
813
814
815

      /* We want to be a process group leader */
      if (setsid() < 0)
	{
	  werror("unix_user: setsid failed, already process group leader?\n"
		 "   %e\n", errno);
	  _exit(EXIT_FAILURE);
	}
Niels Möller's avatar
Niels Möller committed
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
      
#if WITH_PTY_SUPPORT
      if (info->pty)
	{
	  debug("lshd: unix_user.c: Opening slave tty...\n");
	  if ( (tty = pty_open_slave(info->pty)) < 0)
	    {
	      debug("lshd: unix_user.c: "
		    "Opening slave tty... Failed!\n");
	      werror("lshd: Can't open controlling tty for child!\n");
	      _exit(EXIT_FAILURE);
	    }
	  else
	    debug("lshd: unix_user.c: Opening slave tty... Ok.\n");
	}
#endif /* WITH_PTY_SUPPORT */
832
833
834

      trace("do_spawn: child after pty\n");
      
Niels Möller's avatar
Niels Möller committed
835
836
837
      /* Now any tty processing is done, so notify our parent by
       * closing the syncronization pipe. */
      
838
      safe_close(sync[0]); safe_close(sync[1]);
Niels Möller's avatar
Niels Möller committed
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853

#define DUP_FD_OR_TTY(src, dst) dup2((src) >= 0 ? (src) : tty, dst)

      if (DUP_FD_OR_TTY(info->in[0], STDIN_FILENO) < 0)
	{
	  werror("Can't dup stdin!\n");
	  _exit(EXIT_FAILURE);
	}

      if (DUP_FD_OR_TTY(info->out[1], STDOUT_FILENO) < 0)
	{
	  werror("Can't dup stdout!\n");
	  _exit(EXIT_FAILURE);
	}

854
      trace("do_spawn: child before stderr dup\n");
Niels Möller's avatar
Niels Möller committed
855
856
857
858
859
860
861
862
863
864
865
866
867
      if (!dup_error_stream())
	{
	  werror("unix_user.c: Failed to dup old stderr. Bye.\n");
	  set_error_ignore();
	}

      if (DUP_FD_OR_TTY(info->err[1], STDERR_FILENO) < 0)
	{
	  werror("Can't dup stderr!\n");
	  _exit(EXIT_FAILURE);
	}
#undef DUP_FD_OR_TTY
      
868
869
      trace("do_spawn: child after stderr dup\n");

870
871
872
873
874
875
      /* Close all the fd:s, except ones that are -1 */
      safe_close(info->in[0]);
      safe_close(info->in[1]);
      safe_close(info->out[0]);
      safe_close(info->out[1]);
      safe_close(info->err[0]);
876
877
878
879
880
      /* Allow the client's stdout and stderr to be the same fd, e.g.
       * both /dev/null. */
      if (info->err[1] != info->out[1])
	safe_close(info->err[1]);

881
      safe_close(tty);
Niels Möller's avatar
Niels Möller committed
882
883
884
885
886
887
      
      exec_shell(user, info);
      _exit(EXIT_FAILURE);
    }
}

888
static struct lsh_user *
889
890
make_unix_user(struct lsh_string *name,
	       uid_t uid, gid_t gid,
891
	       struct unix_user_db *ctx,
892
893
894
895
896
897
	       const char *passwd,
	       const char *home,
	       const char *shell)
{
  NEW(unix_user, user);
  
898
  assert(lsh_get_cstring(name));
899
900
901
902

  user->super.name = name;
  user->super.verify_password = do_verify_password;
  user->super.file_exists = do_file_exists;
903
  user->super.read_file = do_read_file;
904
  user->super.spawn = do_spawn;
905
906
907
908
  
  user->super.uid = uid;
  user->gid = gid;

909
  user->ctx = ctx;
910
  
911
912
  /* Treat empty strings as NULL. */

913
914
915
916
917
#define STRING(s) (((s) && *(s)) ? make_string((s)) : NULL)
  user->passwd = STRING(passwd);
  user->home = STRING(home);
  user->shell = STRING(shell);
#undef STRING
918
919
920
921
922
923
924
925
926
  
  return &user->super;
}
			    
/* GABA:
   (class
     (name unix_user_db)
     (super user_db)
     (vars
Niels Möller's avatar
Niels Möller committed
927
       (reaper object reaper)
928
929

       ; A program to use for verifying passwords.
930
       (pw_helper . "const char *")
931
932
933
934

       ; Override the login shell for all users.
       (login_shell . "const char *")
       
935
936
937
938
       (allow_root . int)))
*/


939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
/* It's somewhat tricky to determine when accounts are disabled. To be
 * safe, it is recommended that all disabled accounts have a harmless
 * login-shell, like /bin/false.
 *
 * We return NULL for disabled accounts, according to the following
 * rules:
 *
 * If our uid is non-zero, i.e. we're not running as root, then an
 * account is considered valid if and only if it's uid matches the
 * server's. We never try checking the shadow record.
 *
 * If we're running as root, first check the passwd record.
 *
 * o If the uid is zero, consider the account disabled. --root-login
 *   omits this check.
 *
 * o If the passwd equals "x", look up the shadow record, check
 *   expiration etc, and replace the passwd value with the one from the
 *   shadow record. If there's no shadow record, consider the account
 *   disabled.
959
 *
960
961
962
963
 * o If the passwd field is empty, consider the account disabled (we
 *   usually don't want remote logins on pasword-less accounts). We may
 *   need to make this check optional, though.
 *
964
965
966
967
 * o If the passwd entry starts with a "*" and is longer than one
 *   character, consider the account disabled. (Other bogus values like
 *   "NP" means that the account is enabled, only password login is
 *   disabled)
968
969
970
 *
 * o Otherwise, the account is active, and a user record is returned.
 *
971
972
 * FIXME: What about systems that uses a single "*" to disable
 * accounts?
973
974
 */

975
static struct lsh_user *
976
977
978
979
980
981
do_lookup_user(struct user_db *s,
	       struct lsh_string *name, int free)
{
  CAST(unix_user_db, self, s);
  
  struct passwd *passwd;
Niels Möller's avatar
Niels Möller committed
982
  const char *home;
983
  const char *shell;
984
  const char *cname = lsh_get_cstring(name);
985
986
987
  char *crypted;
  uid_t me;

988
989
990
991
992
993
  if (!cname)
    {
      if (free)
	lsh_string_free(name);
      return NULL;
    }
994
995
996
997
998
999
1000

  me = getuid();
  passwd = getpwnam(cname);

  if (!passwd)
    {
    fail: