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

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