source: trunk/third/ssh/userfile.c @ 12646

Revision 12646, 27.9 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12645, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2
3userfile.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8                   All rights reserved
9
10Created: Wed Jan 24 20:19:53 1996 ylo
11
12*/
13
14/*
15 * $Log: not supported by cvs2svn $
16 * Revision 1.18  1998/05/23  20:28:26  kivinen
17 *      Changed () -> (void).
18 *
19 * Revision 1.17  1998/04/17  00:43:08  kivinen
20 *      Freebsd login capabilities support.
21 *
22 * Revision 1.16  1997/05/13 22:30:05  kivinen
23 *      Added some casts.
24 *
25 * Revision 1.15  1997/03/26 07:10:04  kivinen
26 *      Changed uid 0 to UID_ROOT.
27 *
28 * Revision 1.14  1997/03/25 05:47:00  kivinen
29 *      Changed USERFILE_GET_DES_1_MAGIC_PHRASE to call
30 *      userfile_get_des_1_magic_phrase.
31 *
32 * Revision 1.13  1997/03/19 17:53:46  kivinen
33 *      Added USERFILE_GET_DES_1_MAGIC_PHRASE.
34 *
35 * Revision 1.12  1996/11/27 14:30:07  ttsalo
36 *     Added group-writeability #ifdef
37 *
38 * Revision 1.11  1996/10/29 22:48:23  kivinen
39 *      Removed USERFILE_LOCAL_SOCK and USERFILE_SEND.
40 *
41 * Revision 1.10  1996/10/07 11:40:20  ttsalo
42 *      Configuring for hurd and a small fix to do_popen()
43 *      from "Charles M. Hannum" <mycroft@gnu.ai.mit.edu> added.
44 *
45 * Revision 1.9  1996/10/04 01:01:49  kivinen
46 *      Added printing of path to fatal calls in userfile_open and and
47 *      userfile_local_socket_connect. Fixed userfile_open to
48 *      userfile_local_socket_connect in calls to fatal in
49 *      userfile_local_socket_connect.
50 *
51 * Revision 1.8  1996/09/27 17:18:06  ylo
52 *      Fixed a typo.
53 *
54 * Revision 1.7  1996/09/08 17:21:08  ttsalo
55 *      A lot of changes in agent-socket handling
56 *
57 * Revision 1.6  1996/09/04 12:39:59  ttsalo
58 *      Added connecting to unix-domain socket
59 *
60 * Revision 1.5  1996/08/13 09:04:19  ttsalo
61 *      Home directory, .ssh and .ssh/authorized_keys are now
62 *      checked for wrong owner and group & world writeability.
63 *
64 * Revision 1.4  1996/05/29 07:37:31  ylo
65 *      Do setgid and initgroups when initializing to read as user.
66 *
67 * Revision 1.3  1996/04/26 18:10:45  ylo
68 *      Wrong file descriptors were closed in the forked child in
69 *      do_popen.  This caused dup2 to fail on some machines, which in
70 *      turn resulted in X11 authentication failing on some machines.
71 *
72 * Revision 1.2  1996/02/18 21:48:46  ylo
73 *      Close pipes after popen fork.
74 *      New function userfile_close_pipes.
75 *
76 * Revision 1.1.1.1  1996/02/18 21:38:11  ylo
77 *      Imported ssh-1.2.13.
78 *
79 * $EndLog$
80 */
81
82/* Protocol for communication between the child and the parent:
83
84      Each message starts with a 32-bit length (msb first; includes
85      type but not length itself), followed by one byte containing
86      the packet type.
87
88        1 USERFILE_OPEN
89          string        file name
90          int32         flags
91          int32         mode
92
93        2 USERFILE_OPEN_REPLY
94          int32         handle (-1 if error)
95
96        3 USERFILE_READ
97          int32         handle
98          int32         max_bytes
99
100        4 USERFILE_READ_REPLY
101          string        data      ;; empty data means EOF
102
103        5 USERFILE_WRITE
104          int32         handle
105          string        data
106
107        6 USERFILE_WRITE_REPLY
108          int32         bytes_written  ;; != length of data means error
109       
110        7 USERFILE_CLOSE
111          int32         handle
112
113        8 USERFILE_CLOSE_REPLY
114          int32         return value
115
116        9 USERFILE_LSEEK
117          int32         handle
118          int32         offset
119          int32         whence
120
121       10 USERFILE_LSEEK_REPLY
122          int32         returned_offset
123
124       11 USERFILE_MKDIR
125          string        path
126          int32         mode
127
128       12 USERFILE_MKDIR_REPLY
129          int32         return value
130
131       13 USERFILE_STAT
132          string        path
133
134       14 USERFILE_STAT_REPLY
135          int32         return value
136          sizeof(struct stat) binary bytes (in host order and layout)
137
138       15 USERFILE_REMOVE
139          string        path
140
141       16 USERFILE_REMOVE_REPLY
142          int32         return value
143
144       17 USERFILE_POPEN
145          string        command
146          string        type
147
148       18 USERFILE_POPEN_REPLY
149          int32         handle (-1 if error)
150
151       19 USERFILE_PCLOSE
152          int32         handle
153
154       20 USERFILE_PCLOSE_REPLY
155          int32         return value
156
157       21 USERFILE_GET_DES_1_MAGIC_PHRASE
158
159       22 USERFILE_GET_DES_1_MAGIC_PHRASE_REPLY
160          string        data
161         
162          */
163
164#include "includes.h"
165#include <gmp.h>
166#include "userfile.h"
167#include "getput.h"
168#include "buffer.h"
169#include "bufaux.h"
170#include "xmalloc.h"
171#include "ssh.h"
172
173#ifdef SECURE_RPC
174#include <rpc/rpc.h>
175#endif
176
177
178#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
179#include <login_cap.h>
180#endif
181
182/* Protocol message types. */
183#define USERFILE_OPEN           1
184#define USERFILE_OPEN_REPLY     2
185#define USERFILE_READ           3
186#define USERFILE_READ_REPLY     4
187#define USERFILE_WRITE          5
188#define USERFILE_WRITE_REPLY    6
189#define USERFILE_CLOSE          7
190#define USERFILE_CLOSE_REPLY    8
191#define USERFILE_LSEEK          9
192#define USERFILE_LSEEK_REPLY   10
193#define USERFILE_MKDIR         11
194#define USERFILE_MKDIR_REPLY   12
195#define USERFILE_STAT          13
196#define USERFILE_STAT_REPLY    14
197#define USERFILE_REMOVE        15
198#define USERFILE_REMOVE_REPLY  16
199#define USERFILE_POPEN         17
200#define USERFILE_POPEN_REPLY   18
201#define USERFILE_PCLOSE        19
202#define USERFILE_PCLOSE_REPLY  20
203#define USERFILE_GET_DES_1_MAGIC_PHRASE        21
204#define USERFILE_GET_DES_1_MAGIC_PHRASE_REPLY  22
205
206
207/* Flag indicating whether we have forked. */
208static int userfile_initialized = 0;
209
210/* The uid under which the child is running. */
211static uid_t userfile_uid = -1;
212
213/* Communication pipes. */
214static int userfile_tochild;
215static int userfile_fromchild;
216static int userfile_toparent;
217static int userfile_fromparent;
218
219/* Aliases to above; set up depending on whether running as the server or
220   the child. */
221static int userfile_output;
222static int userfile_input;
223
224/* Buffer for a packet. */
225static Buffer packet;
226static int packet_initialized = 0;
227
228/* Starts constructing a packet.  Stores the type into the packet. */
229
230static void userfile_packet_start(int type)
231{
232  if (!packet_initialized)
233    {
234      buffer_init(&packet);
235      packet_initialized = 1;
236    }
237 
238  buffer_clear(&packet);
239  buffer_put_char(&packet, type);
240}
241
242/* Sends a packet that has been constructed in "packet". */
243 
244static void userfile_packet_send(void)
245{
246  unsigned char lenbuf[4];
247  unsigned int len, offset;
248  int bytes;
249
250  len = buffer_len(&packet);
251  PUT_32BIT(lenbuf, len);
252  len = 4;
253  for (offset = 0; offset < len; offset += bytes)
254    {
255      bytes = write(userfile_output, lenbuf + offset, len - offset);
256      if (bytes <= 0)
257        fatal("userfile_packet_send: child has died: %s", strerror(errno));
258    }
259 
260  len = buffer_len(&packet);
261  for (offset = 0; offset < len; offset += bytes)
262    {
263      bytes = write(userfile_output, buffer_ptr(&packet) + offset,
264                    len - offset);
265      if (bytes <= 0)
266        fatal("userfile_packet_send: child has died: %s", strerror(errno));
267    }
268}
269
270/* Reads a packet from the other side.  Returns the packet type. */
271
272static int userfile_read_raw(void)
273{
274  unsigned char buf[512];
275  unsigned int len, offset;
276  int bytes;
277
278  if (!packet_initialized)
279    {
280      buffer_init(&packet);
281      packet_initialized = 1;
282    }
283
284  len = 4;
285  for (offset = 0; offset < len; offset += bytes)
286    {
287      bytes = read(userfile_input, buf + offset, len - offset);
288      if (bytes <= 0)
289        {
290          if (getuid() == geteuid()) /* presumably child - be quiet */
291            exit(0);
292          fatal("userfile_read_raw: child has died: %s", strerror(errno));
293        }
294    }
295
296  len = GET_32BIT(buf);
297  if (len > 32000)
298    fatal("userfile_read_raw: received packet too long.");
299 
300  buffer_clear(&packet);
301  for (offset = 0; offset < len; offset += bytes)
302    {
303      bytes = len - offset;
304      if (bytes > sizeof(buf))
305        bytes = sizeof(buf);
306      bytes = read(userfile_input, buf, bytes);
307      if (bytes <= 0)
308        fatal("userfile_read_raw: child has died: %s", strerror(errno));
309      buffer_append(&packet, (char *) buf, bytes);
310    }
311  return buffer_get_char(&packet);
312}
313
314/* Reads a packet from the child.  The packet should be of expected_type. */
315
316static void userfile_packet_read(int expected_type)
317{
318  int type;
319
320  type = userfile_read_raw();
321  if (type != expected_type)
322    fatal("userfile_read_packet: unexpected packet type: got %d, expected %d",
323          type, expected_type);
324}
325
326/* Forks and execs the given command.  Returns a file descriptor for
327   communicating with the program, or -1 on error.  The program will
328   be run with empty environment to avoid LD_LIBRARY_PATH and similar
329   attacks. */
330
331int do_popen(const char *command, const char *type)
332{
333  int fds[2];
334  int pid, i, j;
335  char *args[100];
336  char *env[100];
337  extern char **environ;
338 
339  if (pipe(fds) < 0)
340    fatal("pipe: %s", strerror(errno));
341 
342  pid = fork();
343  if (pid < 0)
344    fatal("fork: %s", strerror(errno));
345 
346  if (pid == 0)
347    { /* Child */
348
349      /* Close pipes to the parent; we do not wish to disclose them to a
350         random user program. */
351      close(userfile_fromparent);
352      close(userfile_toparent);
353
354      /* Set up file descriptors. */
355      if (type[0] == 'r')
356        {
357          if (dup2(fds[1], 1) < 0)
358            perror("dup2 1");
359        }
360      else
361        {
362          if (dup2(fds[0], 0) < 0)
363            perror("dup2 0");
364        }
365      close(fds[0]);
366      close(fds[1]);
367
368      /* Build argument vector. */
369      i = 0;
370      args[i++] = "/bin/sh";
371      args[i++] = "-c";
372      args[i++] = (char *)command;
373      args[i++] = NULL;
374
375      /* Prune environment to remove any potentially dangerous variables. */
376      i = 0;
377      for (j = 0; environ[j] && i < sizeof(env)/sizeof(env[0]) - 1; j++)
378        if (strncmp(environ[j], "HOME=", 5) == 0 ||
379            strncmp(environ[j], "USER=", 5) == 0 ||
380            strncmp(environ[j], "HOME=", 5) == 0 ||
381            strncmp(environ[j], "PATH=", 5) == 0 ||
382            strncmp(environ[j], "LOGNAME=", 8) == 0 ||
383            strncmp(environ[j], "TZ=", 3) == 0 ||
384            strncmp(environ[j], "MAIL=", 5) == 0 ||
385            strncmp(environ[j], "SHELL=", 6) == 0 ||
386            strncmp(environ[j], "TERM=", 5) == 0 ||
387            strncmp(environ[j], "DISPLAY=", 8) == 0 ||
388            strncmp(environ[j], "PRINTER=", 8) == 0 ||
389            strncmp(environ[j], "XAUTHORITY=", 11) == 0 ||
390            strncmp(environ[j], "TERMCAP=", 8) == 0)
391          env[i++] = environ[j];
392      env[i] = NULL;
393
394      execve("/bin/sh", args, env);
395      fatal("execv /bin/sh failed: %s", strerror(errno));
396    }
397
398  /* Parent. */
399  if (type[0] == 'r')
400    { /* It is for reading. */
401      close(fds[1]);
402      return fds[0];
403    }
404  else
405    { /* It is for writing. */
406      close(fds[0]);
407      return fds[1];
408    }
409}
410
411/* This function is the main loop of the child.  This never returns. */
412
413static void userfile_child_server(void)
414{
415  int type, handle, ret, ret2;
416  unsigned int max_bytes, flags, len, whence;
417  mode_t mode;
418  off_t offset;
419  char *path, *cp, *command;
420  char buf[8192];
421  struct stat st;
422
423  for (;;)
424    {
425      type = userfile_read_raw();
426      switch (type)
427        {
428        case USERFILE_OPEN:
429          path = buffer_get_string(&packet, NULL);
430          flags = buffer_get_int(&packet);
431          mode = buffer_get_int(&packet);
432
433          ret = open(path, flags, mode);
434
435          userfile_packet_start(USERFILE_OPEN_REPLY);
436          buffer_put_int(&packet, ret);
437          userfile_packet_send();
438
439          xfree(path);
440          break;
441
442        case USERFILE_READ:
443          handle = buffer_get_int(&packet);
444          max_bytes = buffer_get_int(&packet);
445
446          if (max_bytes >= sizeof(buf))
447            max_bytes = sizeof(buf);
448          ret = read(handle, buf, max_bytes);
449          if (ret < 0)
450            ret = 0;
451
452          userfile_packet_start(USERFILE_READ_REPLY);
453          buffer_put_string(&packet, buf, ret);
454          userfile_packet_send();
455
456          break;
457         
458        case USERFILE_WRITE:
459          handle = buffer_get_int(&packet);
460          cp = buffer_get_string(&packet, &len);
461
462          ret = write(handle, cp, len);
463
464          userfile_packet_start(USERFILE_WRITE_REPLY);
465          buffer_put_int(&packet, ret);
466          userfile_packet_send();
467
468          xfree(cp);
469          break;
470
471        case USERFILE_CLOSE:
472          handle = buffer_get_int(&packet);
473
474          ret = close(handle);
475
476          userfile_packet_start(USERFILE_CLOSE_REPLY);
477          buffer_put_int(&packet, ret);
478          userfile_packet_send();
479
480          break;
481
482        case USERFILE_LSEEK:
483          handle = buffer_get_int(&packet);
484          offset = buffer_get_int(&packet);
485          whence = buffer_get_int(&packet);
486
487          ret = lseek(handle, offset, whence);
488
489          userfile_packet_start(USERFILE_LSEEK_REPLY);
490          buffer_put_int(&packet, ret);
491          userfile_packet_send();
492
493          break;
494
495        case USERFILE_MKDIR:
496          path = buffer_get_string(&packet, NULL);
497          mode = buffer_get_int(&packet);
498
499          ret = mkdir(path, mode);
500
501          userfile_packet_start(USERFILE_MKDIR_REPLY);
502          buffer_put_int(&packet, ret);
503          userfile_packet_send();
504
505          xfree(path);
506          break;
507
508        case USERFILE_STAT:
509          path = buffer_get_string(&packet, NULL);
510
511          ret = stat(path, &st);
512
513          userfile_packet_start(USERFILE_STAT_REPLY);
514          buffer_put_int(&packet, ret);
515          buffer_append(&packet, (void *)&st, sizeof(st));
516          userfile_packet_send();
517
518          xfree(path);
519          break;
520         
521        case USERFILE_REMOVE:
522          path = buffer_get_string(&packet, NULL);
523
524          ret = remove(path);
525
526          userfile_packet_start(USERFILE_REMOVE_REPLY);
527          buffer_put_int(&packet, ret);
528          userfile_packet_send();
529
530          xfree(path);
531          break;
532
533        case USERFILE_POPEN:
534          command = buffer_get_string(&packet, NULL);
535          cp = buffer_get_string(&packet, NULL);
536
537          ret = do_popen(command, cp);
538
539          userfile_packet_start(USERFILE_POPEN_REPLY);
540          buffer_put_int(&packet, ret);
541          userfile_packet_send();
542
543          xfree(command);
544          xfree(cp);
545          break;
546
547        case USERFILE_PCLOSE:
548          handle = buffer_get_int(&packet);
549
550          ret = close(handle);
551          ret2 = wait(NULL);
552          if (ret >= 0)
553            ret = ret2;
554
555          userfile_packet_start(USERFILE_PCLOSE_REPLY);
556          buffer_put_int(&packet, ret);
557          userfile_packet_send();
558
559          break;
560
561        case USERFILE_GET_DES_1_MAGIC_PHRASE:
562          {
563            char *buf = NULL;
564#ifdef SECURE_RPC
565            buf = userfile_get_des_1_magic_phrase(geteuid());
566#endif
567            userfile_packet_start(USERFILE_GET_DES_1_MAGIC_PHRASE_REPLY);
568            if (buf == NULL)
569              buffer_put_string(&packet, "", 0);
570            else
571              {
572                buffer_put_string(&packet, buf, strlen(buf));
573                memset(buf, 0, strlen(buf));
574              }
575            userfile_packet_send();
576          }
577          break;
578
579        default:
580          fatal("userfile_child_server: packet type %d", type);
581        }
582    }
583}
584
585/* Initializes reading as a user.  Before calling this, I/O may only be
586   performed as the user that is running the current program (current
587   effective uid).  SIGPIPE should be set to ignored before this call.
588   The cleanup callback will be called in the child before switching to the
589   user's uid.  The callback may be NULL. */
590
591void userfile_init(const char *username, uid_t uid, gid_t gid,
592                   void (*cleanup_callback)(void *), void *context)
593{
594  int fds[2], pid;
595
596  if (userfile_initialized)
597    fatal("userfile_init already called");
598 
599  userfile_uid = uid;
600  userfile_initialized = 1;
601
602  if (pipe(fds) < 0)
603    fatal("pipe: %s", strerror(errno));
604  userfile_tochild = fds[1];
605  userfile_fromparent = fds[0];
606 
607  if (pipe(fds) < 0)
608    fatal("pipe: %s", strerror(errno));
609  userfile_fromchild = fds[0];
610  userfile_toparent = fds[1];
611 
612  pid = fork();
613  if (pid < 0)
614    fatal("fork: %s", strerror(errno));
615
616  if (pid != 0)
617    {
618      /* Parent. */
619      userfile_input = userfile_fromchild;
620      userfile_output = userfile_tochild;
621      close(userfile_toparent);
622      close(userfile_fromparent);
623      return;
624    }
625
626  /* Child. */
627  userfile_input = userfile_fromparent;
628  userfile_output = userfile_toparent;
629  close(userfile_tochild);
630  close(userfile_fromchild);
631
632  /* Call the cleanup callback if given. */
633  if (cleanup_callback)
634    (*cleanup_callback)(context);
635 
636  /* Reset signals to their default settings. */
637  signals_reset();
638
639  /* Child.  We will start serving request. */
640  if (uid != geteuid() || uid != getuid())
641    {
642#if defined (__FreeBSD__) && defined(HAVE_LOGIN_CAP_H)
643      struct passwd * pw = getpwuid(uid);
644      login_cap_t * lc = login_getuserclass(pw);
645      if (setusercontext(lc, pw, uid,
646                         LOGIN_SETALL & ~(LOGIN_SETLOGIN | LOGIN_SETPATH |
647                                          LOGIN_SETENV)) < 0)
648        fatal("setusercontext: %s", strerror(errno));
649#else
650      if (setgid(gid) < 0)
651        fatal("setgid: %s", strerror(errno));
652
653#ifdef HAVE_INITGROUPS
654      if (initgroups((char *) username, gid) < 0)
655        fatal("initgroups: %s", strerror(errno));
656#endif /* HAVE_INITGROUPS */
657
658      if (setuid(uid) < 0)
659        fatal("setuid: %s", strerror(errno));
660#endif /* HAVE_LOGIN_CAP_H */
661    }
662
663  /* Enter the server main loop. */
664  userfile_child_server();
665}
666
667/* Closes any open pipes held by userfile.  This should be called
668   after a fork while the userfile is open. */
669
670void userfile_close_pipes(void)
671{
672  if (!userfile_initialized)
673    return;
674  userfile_initialized = 0;
675  close(userfile_fromchild);
676  close(userfile_tochild);
677}
678
679/* Stops reading files as an ordinary user.  It is not an error to call
680   this even if the system is not initialized. */
681
682void userfile_uninit(void)
683{
684  int status;
685
686  if (!userfile_initialized)
687    return;
688 
689  userfile_close_pipes();
690
691  wait(&status);
692}
693
694/* Data structure for UserFiles. */
695
696struct UserFile
697{
698  enum { USERFILE_LOCAL, USERFILE_REMOTE } type;
699  int handle; /* Local: file handle; remote: index to descriptor array. */
700  unsigned char buf[512];
701  unsigned int buf_first;
702  unsigned int buf_last;
703};
704
705/* Allocates a UserFile handle and initializes it. */
706
707static UserFile userfile_make_handle(int type, int handle)
708{
709  UserFile uf;
710
711  uf = xmalloc(sizeof(*uf));
712  uf->type = type;
713  uf->handle = handle;
714  uf->buf_first = 0;
715  uf->buf_last = 0;
716  return uf;
717}
718
719/* Encapsulate a normal file descriptor inside a struct UserFile */
720UserFile userfile_encapsulate_fd(int fd)
721{
722  return userfile_make_handle(USERFILE_LOCAL, fd);
723}
724
725/* Opens a file using the given uid.  The uid must be either the current
726   effective uid (in which case userfile_init need not have been called) or
727   the uid passed to a previous call to userfile_init.  Returns a pointer
728   to a structure, or NULL if an error occurred.  The flags and mode arguments
729   are identical to open(). */
730
731UserFile userfile_open(uid_t uid, const char *path, int flags, mode_t mode)
732{
733  int handle;
734
735  if (uid == geteuid())
736    {
737      handle = open(path, flags, mode);
738      if (handle < 0)
739        return NULL;
740      return userfile_make_handle(USERFILE_LOCAL, handle);
741    }
742
743  if (!userfile_initialized)
744    fatal("userfile_open: using non-current uid but not initialized (uid=%d, path=%.50s)",
745          (int)uid, path);
746 
747  if (uid != userfile_uid)
748    fatal("userfile_open: uid not current and not that of child: uid=%d, path=%.50s",
749          (int)uid, path);
750
751  userfile_packet_start(USERFILE_OPEN);
752  buffer_put_string(&packet, path, strlen(path));
753  buffer_put_int(&packet, flags);
754  buffer_put_int(&packet, mode);
755  userfile_packet_send();
756
757  userfile_packet_read(USERFILE_OPEN_REPLY);
758  handle = buffer_get_int(&packet);
759  if (handle < 0)
760    return NULL;
761
762  return userfile_make_handle(USERFILE_REMOTE, handle);
763}
764
765/* Closes the userfile handle.  Returns >= 0 on success, and < 0 on error. */
766
767int userfile_close(UserFile uf)
768{
769  int ret;
770
771  switch (uf->type)
772    {
773    case USERFILE_LOCAL:
774      ret = close(uf->handle);
775      xfree(uf);
776      return ret;
777
778    case USERFILE_REMOTE:
779      userfile_packet_start(USERFILE_CLOSE);
780      buffer_put_int(&packet, uf->handle);
781      userfile_packet_send();
782     
783      userfile_packet_read(USERFILE_CLOSE_REPLY);
784      ret = buffer_get_int(&packet);
785
786      xfree(uf);
787      return ret;
788
789    default:
790      fatal("userfile_close: type %d", uf->type);
791      /*NOTREACHED*/
792      return -1;
793    }
794}
795
796/* Get more data from the child into the buffer.  Returns false if no more
797   data is available (EOF). */
798
799static int userfile_fill(UserFile uf)
800{
801  unsigned int len;
802  char *cp;
803  int ret;
804
805  if (uf->buf_first < uf->buf_last)
806    fatal("userfile_fill: buffer not empty");
807
808  switch (uf->type)
809    {
810    case USERFILE_LOCAL:
811      ret = read(uf->handle, uf->buf, sizeof(uf->buf));
812      if (ret <= 0)
813        return 0;
814      uf->buf_first = 0;
815      uf->buf_last = ret;
816      break;
817
818    case USERFILE_REMOTE:
819      userfile_packet_start(USERFILE_READ);
820      buffer_put_int(&packet, uf->handle);
821      buffer_put_int(&packet, sizeof(uf->buf));
822      userfile_packet_send();
823
824      userfile_packet_read(USERFILE_READ_REPLY);
825      cp = buffer_get_string(&packet, &len);
826      if (len > sizeof(uf->buf))
827        fatal("userfile_fill: got more than data than requested");
828      memcpy(uf->buf, cp, len);
829      xfree(cp);
830      if (len == 0)
831        return 0;
832      uf->buf_first = 0;
833      uf->buf_last = len;
834      break;
835
836    default:
837      fatal("userfile_fill: type %d", uf->type);
838    }
839
840  return 1;
841}
842
843/* Returns the next character from the file (as an unsigned integer) or -1
844   if an error is encountered. */
845
846int userfile_getc(UserFile uf)
847{
848  if (uf->buf_first >= uf->buf_last)
849    {
850      if (!userfile_fill(uf))
851        return -1;
852     
853      if (uf->buf_first >= uf->buf_last)
854        fatal("userfile_getc/fill error");
855    }
856 
857  return uf->buf[uf->buf_first++];
858}
859
860/* Reads data from the file.  Returns as much data as is the buffer
861   size, unless end of file is encountered.  Returns the number of bytes
862   read, 0 on EOF, and -1 on error. */
863
864int userfile_read(UserFile uf, void *buf, unsigned int len)
865{
866  unsigned int i;
867  int ch;
868  unsigned char *ucp;
869 
870  ucp = buf;
871  for (i = 0; i < len; i++)
872    {
873      ch = userfile_getc(uf);
874      if (ch == -1)
875        break;
876      ucp[i] = ch;
877    }
878 
879  return i;
880}
881
882/* Writes data to the file.  Writes all data, unless an error is encountered.
883   Returns the number of bytes actually written; -1 indicates error. */
884
885int userfile_write(UserFile uf, const void *buf, unsigned int len)
886{
887  unsigned int chunk_len, offset;
888  int ret;
889  const unsigned char *ucp;
890
891  switch (uf->type)
892    {
893    case USERFILE_LOCAL:
894      return write(uf->handle, buf, len);
895     
896    case USERFILE_REMOTE:
897      ucp = buf;
898      for (offset = 0; offset < len; )
899        {
900          chunk_len = len - offset;
901          if (chunk_len > 16000)
902            chunk_len = 16000;
903         
904          userfile_packet_start(USERFILE_WRITE);
905          buffer_put_int(&packet, uf->handle);
906          buffer_put_string(&packet, ucp + offset, chunk_len);
907          userfile_packet_send();
908         
909          userfile_packet_read(USERFILE_WRITE_REPLY);
910          ret = buffer_get_int(&packet);
911          if (ret < 0)
912            return -1;
913          offset += ret;
914          if (ret != chunk_len)
915            break;
916        }
917      return offset;
918
919    default:
920      fatal("userfile_write: type %d", uf->type);
921      /*NOTREACHED*/
922      return 0;
923    }
924}
925
926/* Reads a line from the file.  The line will be null-terminated, and
927   will include the newline.  Returns a pointer to the given buffer,
928   or NULL if no more data was available.  If a line is too long,
929   reads as much as the buffer can accommodate (and null-terminates
930   it).  If the last line of the file does not terminate with a
931   newline, returns the line, null-terminated, but without a
932   newline. */
933
934char *userfile_gets(char *buf, unsigned int size, UserFile uf)
935{
936  unsigned int i;
937  int ch;
938
939  for (i = 0; i < size - 1; )
940    {
941      ch = userfile_getc(uf);
942      if (ch == -1)
943        break;
944      buf[i++] = ch;
945      if (ch == '\n')
946        break;
947    }
948  if (i == 0)
949    return NULL;
950
951  buf[i] = '\0';
952 
953  return buf;
954}
955
956/* Performs lseek() on the given file. */
957
958off_t userfile_lseek(UserFile uf, off_t offset, int whence)
959{
960  switch (uf->type)
961    {
962    case USERFILE_LOCAL:
963      return lseek(uf->handle, offset, whence);
964     
965    case USERFILE_REMOTE:
966      userfile_packet_start(USERFILE_LSEEK);
967      buffer_put_int(&packet, uf->handle);
968      buffer_put_int(&packet, offset);
969      buffer_put_int(&packet, whence);
970      userfile_packet_send();
971
972      userfile_packet_read(USERFILE_LSEEK_REPLY);
973      return buffer_get_int(&packet);
974
975    default:
976      fatal("userfile_lseek: type %d", uf->type);
977      /*NOTREACHED*/
978      return 0;
979    }
980}
981
982/* Creates a directory using the given uid. */
983
984int userfile_mkdir(uid_t uid, const char *path, mode_t mode)
985{
986  /* Perform directly if with current effective uid. */
987  if (uid == geteuid())
988    return mkdir(path, mode);
989
990  if (!userfile_initialized)
991    fatal("userfile_mkdir with uid %d", (int)uid);
992 
993  if (uid != userfile_uid)
994    fatal("userfile_mkdir with wrong uid %d", (int)uid);
995
996  userfile_packet_start(USERFILE_MKDIR);
997  buffer_put_string(&packet, path, strlen(path));
998  buffer_put_int(&packet, mode);
999  userfile_packet_send();
1000
1001  userfile_packet_read(USERFILE_MKDIR_REPLY);
1002  return buffer_get_int(&packet);
1003}
1004
1005/* Performs stat() using the given uid. */
1006
1007int userfile_stat(uid_t uid, const char *path, struct stat *st)
1008{
1009  int ret;
1010
1011  /* Perform directly if with current effective uid. */
1012  if (uid == geteuid())
1013    return stat(path, st);
1014
1015  if (!userfile_initialized)
1016    fatal("userfile_stat with uid %d", (int)uid);
1017 
1018  if (uid != userfile_uid)
1019    fatal("userfile_stat with wrong uid %d", (int)uid);
1020
1021  userfile_packet_start(USERFILE_STAT);
1022  buffer_put_string(&packet, path, strlen(path));
1023  userfile_packet_send();
1024
1025  userfile_packet_read(USERFILE_STAT_REPLY);
1026  ret = buffer_get_int(&packet);
1027  buffer_get(&packet, (char *)st, sizeof(*st));
1028
1029  return ret;
1030}
1031
1032/* Performs remove() using the given uid. */
1033
1034int userfile_remove(uid_t uid, const char *path)
1035{
1036  /* Perform directly if with current effective uid. */
1037  if (uid == geteuid())
1038    return remove(path);
1039
1040  if (!userfile_initialized)
1041    fatal("userfile_remove with uid %d", (int)uid);
1042 
1043  if (uid != userfile_uid)
1044    fatal("userfile_remove with wrong uid %d", (int)uid);
1045
1046  userfile_packet_start(USERFILE_REMOVE);
1047  buffer_put_string(&packet, path, strlen(path));
1048  userfile_packet_send();
1049
1050  userfile_packet_read(USERFILE_REMOVE_REPLY);
1051  return buffer_get_int(&packet);
1052}
1053
1054/* Performs popen() on the given uid; returns a file from where the output
1055   of the command can be read (type == "r") or to where data can be written
1056   (type == "w"). */
1057
1058UserFile userfile_popen(uid_t uid, const char *command, const char *type)
1059{
1060  int handle;
1061
1062  if (uid == geteuid())
1063    {
1064      handle = do_popen(command, type);
1065      if (handle < 0)
1066        return NULL;
1067      return userfile_make_handle(USERFILE_LOCAL, handle);
1068    }
1069
1070  if (!userfile_initialized)
1071    fatal("userfile_popen: using non-current uid but not initialized (uid=%d)",
1072          (int)uid);
1073 
1074  if (uid != userfile_uid)
1075    fatal("userfile_popen: uid not current and not that of child: uid=%d",
1076          (int)uid);
1077
1078  userfile_packet_start(USERFILE_POPEN);
1079  buffer_put_string(&packet, command, strlen(command));
1080  buffer_put_string(&packet, type, strlen(type));
1081  userfile_packet_send();
1082
1083  userfile_packet_read(USERFILE_POPEN_REPLY);
1084  handle = buffer_get_int(&packet);
1085  if (handle < 0)
1086    return NULL;
1087
1088  return userfile_make_handle(USERFILE_REMOTE, handle);
1089}
1090
1091/* Performs pclose() on the given uid.  Returns <0 if an error occurs. */
1092
1093int userfile_pclose(UserFile uf)
1094{
1095  int ret, ret2;
1096
1097  switch (uf->type)
1098    {
1099    case USERFILE_LOCAL:
1100      ret = close(uf->handle);
1101      ret2 = wait(NULL);
1102      if (ret >= 0)
1103        ret = ret2;
1104      xfree(uf);
1105      return ret;
1106
1107    case USERFILE_REMOTE:
1108      userfile_packet_start(USERFILE_PCLOSE);
1109      buffer_put_int(&packet, uf->handle);
1110      userfile_packet_send();
1111     
1112      userfile_packet_read(USERFILE_PCLOSE_REPLY);
1113      ret = buffer_get_int(&packet);
1114
1115      xfree(uf);
1116      return ret;
1117
1118    default:
1119      fatal("userfile_close: type %d", uf->type);
1120      /*NOTREACHED*/
1121      return -1;
1122    }
1123}
1124
1125/* Get sun des 1 magic phrase */
1126char *userfile_get_des_1_magic_phrase(uid_t uid)
1127{
1128  char *phrase = NULL;
1129#ifndef SECURE_RPC
1130  return phrase;
1131#else
1132  /* Perform directly if with current effective uid. */
1133  if (uid == geteuid())
1134    {
1135      char buf[MAXNETNAMELEN + 1];
1136      des_block block;
1137     
1138      memset(buf, 0, sizeof(buf));
1139      sprintf(buf, "ssh.%04X", geteuid());
1140      memcpy(block.c, buf, sizeof(block.c));
1141      if (getnetname(buf))
1142        {
1143          if (key_encryptsession(buf, &block) == 0)
1144            {
1145              sprintf(buf, "%08X%08X", ntohl(block.key.high),
1146                      ntohl(block.key.low));
1147              memset(block.c, 0, sizeof(block.c));
1148              phrase = xstrdup(buf);
1149              memset(buf, 0, sizeof(buf));
1150            }
1151        }
1152      return phrase;
1153    }
1154 
1155  if (!userfile_initialized)
1156    fatal("userfile_get_des_1_magic_phrase with uid %d", (int)uid);
1157 
1158  if (uid != userfile_uid)
1159    fatal("userfile_get_des_1_magic_phrase with wrong uid %d", (int)uid);
1160
1161  userfile_packet_start(USERFILE_GET_DES_1_MAGIC_PHRASE);
1162  userfile_packet_send();
1163
1164  userfile_packet_read(USERFILE_GET_DES_1_MAGIC_PHRASE_REPLY);
1165  phrase =  buffer_get_string(&packet, NULL);
1166  if (strlen(phrase) == 0)
1167    {
1168      xfree(phrase);
1169      return NULL;
1170    }
1171  return phrase;
1172#endif
1173}
1174
1175
1176int userfile_check_owner_permissions(struct passwd *pw, const char *path)
1177{
1178  struct stat st;
1179  if (userfile_stat(pw->pw_uid, path, &st) < 0)
1180    return 0;
1181
1182  if ((st.st_uid != UID_ROOT && st.st_uid != pw->pw_uid) ||
1183#ifdef ALLOW_GROUP_WRITEABILITY
1184      (st.st_mode & 002) != 0
1185#else
1186      (st.st_mode & 022) != 0
1187#endif
1188      )
1189    return 0;
1190  else
1191    return 1;
1192}
1193
Note: See TracBrowser for help on using the repository browser.