home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckuuid.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  20KB  |  642 lines

  1. /* ckuuid.c, Test program for C-Kermit's uid-managing code. */
  2. /* priv_*() routines by Kristoffer Ericksson (ske) */
  3. /* this program by Frank da Cruz (fdc), 5-26-90 */
  4. /* Modified by Dean Long, 5-28-90 */
  5. /* Modified ske, fdc, 6-10-90 */
  6. /* Modified to check access() and state conclusions, fdc, 12-29-92 */
  7. /* 4.4BSD semantics added by John Kohl <jtk@kolvir.blrc.ma.us> 20 Sep 94 */
  8.  
  9. /*
  10. INSTRUCTIONS
  11.  
  12. Compile and load the program in each of the following ways:
  13.  
  14.    $ cc -DANYBSD -DSAVEDUID -o ckuuid1 ckuuid.c            (1)
  15.    $ cc -DANYBSD -o ckuuid2 ckuuid.c                       (2)
  16.    $ cc -DANYBSD -DNOSETREU -o ckuuid3 ckuuid.c            (3)
  17.    $ cc -DANYBSD -DSETEUID -DNOSETREU -o ckuuid5 ckuuid.c  (4)
  18.    $ cc -o ckuuid4 ckuuid.c                                (5)
  19.  
  20. (1) is for Berkeley-based systems that have setregid() and setreuid() and that
  21.     have the saved-original-effective-uid feature, similar to AT&T System V.
  22.  
  23. (2) is for Berkeley-based systems that have setregid and setreuid, but do not
  24.     have the saved-original-effective-uid feature.
  25.  
  26. (3) is for Berkeley-based systems that don't have setregid() and setreuid().
  27.  
  28. (4) is for BSD4.4 and others that have seteuid()/setegid() and
  29.     saved-original-effective-uid feature.
  30.  
  31. (5) is for all others, including all AT&T-based versions, Xenix, etc.
  32.  
  33. After building the program, run it to make sure that the uid's don't change
  34. (they shouldn't if the program is not setuid'd).
  35.  
  36. Now make the program setuid and setgid to someone else, e.g.:
  37.  
  38.    $ su
  39.    Password: xxxx
  40.    su% chown uucp.uucp ckuuid2
  41.    su% chmod ug+s ckuuid2
  42.    su% exit
  43.  
  44. and then run it, recording the results.  Give the name of a directory (not a
  45. regular file) that you should have write-access to on the command line, e.g.:
  46.  
  47.    $ script
  48.    $ who am i
  49.    $ ls -lg ./ckuuid2
  50.    $ ./ckuuid2 .
  51.    $ exit
  52.  
  53. Read the output and make sure that the uids and gids can be changed back
  54. and forth.
  55.  
  56. In steps 2, 4, and 5, check to see if access() worked correctly when you
  57. have privs turned off.  If it doesn't, try recompiling with -DSW_ACC_ID
  58. (swap IDs for access()) and repeat the above procedure.
  59.  
  60. Please report the results (mail the typescript file) back to me,
  61. fdc@columbia.edu, letting me know exactly what kind of machine you
  62. have, and which version of UNIX.
  63. */ 
  64.  
  65. /* Includes */
  66.  
  67. #include <stdio.h>
  68. #include <sys/stat.h>
  69. #ifndef S_ISDIR
  70. #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  71. #endif /* S_ISDIR */
  72.  
  73. #ifndef UID_T                /* Define these on the CC command */
  74. #define UID_T int            /* line if your compiler complains */
  75. #endif /* UID_T */            /* about mismatched types, e.g. */
  76.                     /* -DUID_T=uid_t -DGID_T=gid_t */
  77. #ifndef GID_T
  78. #define GID_T int
  79. #endif /* GID_T */
  80.  
  81. /* setuid package variables */
  82.  
  83. /* User and group IDs */
  84.  
  85. static int realuid = (UID_T) -1, privuid = (UID_T) -1;
  86. static int realgid = (GID_T) -1, privgid = (GID_T) -1;
  87. static int ttpuid, ttpgid;
  88.  
  89. /* UID-holding variables */
  90.  
  91. int oku = 0;                /* uid switching works ok */
  92. int okg = 0;                /* gid switching works ok */
  93.  
  94. int uida, uidb;                /* Variables for remembering ids... */
  95. int gida, gidb;
  96.  
  97. int euid, egid;
  98. int ruid, rgid;
  99.  
  100. /* Function to get and print the current real and effective uid and gid */
  101.  
  102. chuid() {
  103.     uida = getuid();
  104.     uidb = geteuid();
  105.     printf("     getuid = %d, geteuid = %d\n",uida,uidb);
  106.     gida = getgid();
  107.     gidb = getegid();
  108.     printf("     getgid = %d, getegid = %d\n",gida,gidb);
  109. }
  110.  
  111. /* Main program */
  112.  
  113. struct stat statbuf;
  114. char *myname;
  115.  
  116. main(argc, argv) int argc; char **argv; {
  117.     int x, acc_ok = 1;
  118.     char *path = NULL;
  119.  
  120.     myname = argv[0];
  121.     if (argc < 2)
  122.       usage();
  123.     else
  124.       path = argv[1];
  125.  
  126. /* Announce which options we were compiled with. */
  127.  
  128. #ifndef NOSETREU
  129. #ifndef SETREUID
  130. #define SETREUID
  131. #endif /* SETREUID */
  132. #endif /* NOSETREU */
  133.  
  134. #ifdef BSD
  135. #ifndef ANYBSD
  136. #define ANYBSD
  137. #endif /* ANYBSD */
  138. #endif /* BSD */
  139.  
  140. #ifdef ANYBSD
  141. #ifndef SAVEDUID
  142.       printf("BSD, with SAVEDUID not defined\n");
  143. #else
  144.       printf("BSD, with SAVEDUID defined\n");
  145. #endif
  146. #ifdef NOSETREU
  147.       printf("No setre[ug]id, using set[ug]id\n");
  148. #else
  149.       printf("Using setre[ug]id\n");
  150. #endif
  151. #else
  152.       printf("Not BSD\n");
  153. #endif
  154.  
  155. /* Print uids and gids before, during and after switching back & forth. */
  156.  
  157.     printf("\n1. ids at startup...\n");
  158.     chuid();
  159.     euid = uidb; egid = gidb;
  160.  
  161.     /* Initialize uid package, change to real uid. */
  162.     printf("\n2. changing to real user and group ids...\n");
  163.     x = priv_ini();
  164.     printf("   priv_ini returns %d\n",x);
  165.     chuid();
  166.     if (stat(path,&statbuf) == -1) {    /* Do this after switching to self */
  167.     perror(path);
  168.     exit(1);
  169.     }
  170.     if (!S_ISDIR (statbuf.st_mode)) {
  171.     printf("%s: not a directory\n");
  172.     usage();
  173.     }
  174.     acc_ok = chkaccess(path);
  175.     ruid = uidb; rgid = gidb;
  176.     
  177.     printf("   this program %s setuid\n",(ruid != euid) ? "IS" : "is NOT");
  178.     printf("   this program %s setgid\n",(rgid != egid) ? "IS" : "is NOT");
  179.     if (ruid == euid || rgid == egid) {
  180.     printf("\nprogram is not privileged\n");
  181.     printf("please chown owner AND group and add \"ug+s\" bits\n\n");
  182.     exit(0);
  183.     }
  184.     /* Try to change back to effective uid */
  185.     printf("\n3. changing to original user and group ids...\n");
  186.     x = priv_on();
  187.     printf("   priv_on returns %d\n",x);
  188.     chuid();
  189. #if defined(SAVEDUID) || defined(SETEUID)
  190.     printf("   saved-original-effective-uid feature %s present\n",
  191.        (uidb == euid) ? "IS" : "is NOT");
  192.     printf("   saved-original-effective-gid feature %s present\n",
  193.        (gidb == egid) ? "IS" : "is NOT");
  194. #else
  195.     printf("   original effective uid %s\n",
  196.        (uidb == euid) ? "restored ok" : "NOT restored");
  197.     printf("   original effective gid %s\n",
  198.        (gidb == egid) ? "restored ok" : "NOT restored");
  199. #endif /* SAVEDUID */
  200.     if (uidb != euid || gidb != egid) goto conclude;
  201.  
  202.     oku = okg = 1;            /* Seems OK so far */
  203.  
  204.     /* Change back to real uid */
  205.     printf("\n4. switching back to real ids...\n"); 
  206.     x = priv_off();
  207.     printf("   priv_off returns %d\n",x);
  208.     chuid();
  209.     x = chkaccess(path);
  210.     if (x < 0) acc_ok = x;
  211.     if (uidb != ruid) {
  212.     printf("  FAILURE to restore real uid\n");
  213.     oku = 0;
  214.     goto conclude;
  215.     }
  216.     if (gidb != rgid) {
  217.     printf("  FAILURE to restore real gid\n");
  218.     okg = 0;
  219.     goto conclude;
  220.     }
  221.     printf("   real ids restored ok\n");
  222.  
  223.     /* Change back to real uid, e.g. for a fork */
  224.     printf("\n5. cancelling privileges permanently...\n");
  225.     x = priv_can();
  226.     printf("   priv_can returns %d\n",x);
  227.     chuid();
  228.     x = chkaccess(path);
  229.     if (x < 0) acc_ok = x;
  230. #ifdef FORK
  231.     {
  232.     pid_t pid;
  233.     if (pid = fork()) {
  234.         /* Try to change back to effective uid */
  235.         priv_can();
  236.         printf("\n6. IN FORK: trying to restore canceled privileges\n");
  237.         x = priv_on();
  238.         printf("   priv_on returns %d\n",x);
  239.         chuid();
  240.  
  241.         printf("   privilege cancellation %s\n",
  242.            (uidb == euid || gidb == egid) ? "FAILED" : "SUCCEEDED");
  243.         _exit(0);
  244.     }        
  245.     }
  246. #else
  247.  
  248.     /* Try to change back to effective uid */
  249.     printf("\n6. trying to restore canceled privileges\n");
  250.     x = priv_on();
  251.     printf("   priv_on returns %d\n",x);
  252.     chuid();
  253.  
  254.     printf("   privilege cancellation %s\n",
  255.        (uidb == euid || gidb == egid) ? "FAILED" : "SUCCEEDED");
  256.     if (uidb == euid) oku = 0;
  257.     if (gidb == egid) okg = 0;
  258. #endif /* FORK */
  259.  
  260.     
  261. conclude:
  262.     printf("\nCONCLUSIONS:\n");
  263.     printf("   It %s safe to install C-Kermit setuid.\n",
  264.        oku ? "IS" : "is NOT");
  265.     printf("   It %s safe to install C-Kermit setgid.\n",
  266.        okg ? "IS" : "is NOT");
  267. #ifdef ANYBSD
  268.     printf("...when built in the BSD environment with these options:\n");
  269. #ifdef SAVEDUID
  270.     printf("   -DSAVEDUID included\n");
  271. #else
  272.     printf("   -DSAVEDUID omitted\n");
  273. #endif
  274. #ifdef NOSETREU
  275.     printf("   -DNOSETREU included\n");
  276. #else
  277.     printf("   -DNOSETREU omitted (-DSETREUID implied)\n");
  278. #endif
  279. #ifdef SW_ACC_ID
  280.     printf("   -DSW_ACC_ID included\n");
  281. #else
  282.     printf("   -DSW_ACC_ID omitted\n");
  283. #endif
  284. #ifdef SETEUID
  285.     printf("   -DSETEUID included\n");
  286. #else
  287.     printf("   -DSETEUID omitted\n");
  288. #endif
  289. #else
  290.     printf("...when built in the System V or POSIX environment\n");
  291. #endif /* ANYBSD */
  292.     if (acc_ok != 1) {
  293.     if (acc_ok < 0) {
  294.         printf(
  295. "\nBUT if %s is a directory that you would normally have write\n\
  296. access to, then something is wrong with this system's access() function.\n\n",
  297.            path, path);
  298.         printf("Try rebuilding %s -DSW_ACC_ID.\n",
  299. #ifdef SW_ACC_ID
  300.            "without"
  301. #else
  302.            "with"
  303. #endif /* SW_ACC_ID */
  304.            );
  305.     } else {
  306.         printf("\nAND access() seems to work properly.\n");
  307.     }
  308.     }
  309.     exit(0);
  310. }
  311.   
  312. #ifndef W_OK
  313. #define W_OK 2
  314. #endif /* W_OK */
  315.  
  316. int
  317. chkaccess(path) char *path; {
  318.     int x;
  319.     if (path) {
  320. #ifdef SW_ACC_ID
  321.     printf("   access check: temporarily swapping ids...\n");
  322.     priv_on();
  323.     x = access(path, W_OK);
  324.     priv_off();
  325. #else
  326.     printf("   access check: no temporary id swapping...\n");
  327.     x = access(path, W_OK);
  328. #endif /* SW_ACC_ID */
  329.     printf("   write-access to %s %s\n", path, x ? "FAILED" : "OK");
  330.     return(x);
  331.     }
  332.     return(1);
  333. }
  334.  
  335. /* 
  336.   Starting here is Kristoffer's code, as modified by fdc, dlong, et al.
  337. */
  338.  
  339. /*
  340.   setuid package, by Kristoffer Eriksson, with contributions from Dean
  341.   Long and fdc.
  342. */
  343.  
  344. #ifndef AIX370
  345. extern int getuid(), getgid(), geteuid(), getegid(), getreuid(), getregid();
  346. #endif
  347.  
  348. /*
  349. Subject: Set-user-id
  350. To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
  351. Date: Sat, 21 Apr 90 4:48:25 MES
  352. From: Kristoffer Eriksson <ske@pkmab.se>
  353.  
  354. This is a set of functions to be used in programs that may be run set-user-id
  355. and/or set-group-id. They handle both the case where the program is not run
  356. with such privileges (nothing special happens then), and the case where one
  357. or both of these set-id modes are used.  The program is made to run with the
  358. user's real user and group ids most of the time, except for when more
  359. privileges are needed.  Don't set-user-id to "root".
  360.  
  361. This works on System V and POSIX.  In BSD, it depends on the
  362. "saved-set-user-id" feature.
  363. */
  364.  
  365. #define UID_ROOT 0            /* Root user and group ids */
  366. #define GID_ROOT 0
  367.  
  368. /* P R I V _ I N I  --  Initialize privileges package  */
  369.  
  370. /* Called as early as possible in a set-uid or set-gid program to store the
  371.  * set-to uid and/or gid and step down to the users real uid and gid. The
  372.  * stored id's can be temporarily restored (allowed in System V) during
  373.  * operations that require the privilege.  Most of the time, the program
  374.  * should execute in unpriviliged state, to not impose any security threat.
  375.  *
  376.  * Note: Don't forget that access() always uses the real id:s to determine
  377.  * file access, even with privileges restored.
  378.  *
  379.  * Returns an error mask, with error values or:ed together:
  380.  *   1 if setuid() fails,
  381.  *   2 if setgid() fails, and
  382.  *   4 if the program is set-user-id to "root", which can't be handled.
  383.  *
  384.  * Only the return value 0 indicates real success. In case of failure,
  385.  * those privileges that could be reduced have been, at least, but the
  386.  * program should be halted nonetheless.
  387.  *
  388.  * Also note that these functions do not expect the uid or gid to change
  389.  * without their knowing. It may work if it is only done temporarily, but
  390.  * you're on your own.
  391.  */
  392. int
  393. priv_ini() {
  394.     int err = 0;
  395.  
  396.     /* Save real ID:s. */
  397.     realuid = getuid();
  398.     realgid = getgid();
  399.  
  400.     /* Save current effective ID:s, those set to at program exec. */
  401.     ttpuid = privuid = geteuid();
  402.     ttpgid = privgid = getegid();
  403.  
  404.     /* If running set-uid, go down to real uid, otherwise remember that
  405.      * no privileged uid is available.
  406.      *
  407.      * Exceptions:
  408.      *
  409.      * 1) If the real uid is already "root" and the set-uid uid (the
  410.      * initial effective uid) is not "root", then we would have trouble
  411.      * if we went "down" to "root" here, and then temporarily back to the
  412.      * set-uid uid (not "root") and then again tried to become "root". I
  413.      * think the "saved set-uid" is lost when changing uid from effective
  414.      * uid "root", which changes all uid, not only the effective uid. But
  415.      * in this situation, we can simply go to "root" and stay there all
  416.      * the time. That should give sufficient privilege (understatement!),
  417.      * and give the right uids for subprocesses.
  418.      *
  419.      * 2) If the set-uid (the initial effective uid) is "root", and we
  420.      * change uid to the real uid, we can't change it back to "root" when
  421.      * we need the privilege, for the same reason as in 1). Thus, we can't
  422.      * handle programs that are set-user-id to "root" at all. The program
  423.      * should be halted.  Use some other uid. "root" is probably too
  424.      * privileged for such things, anyway.  (The uid is reverted to the
  425.      * real uid for the lifetime of the program.)
  426.      *
  427.      * These two exceptions have the effect that the "root" uid will never
  428.      * be one of the two uids that are being switched between, which also
  429.      * means we don't have to check for such cases in the switching
  430.      * functions.
  431.      *
  432.      * Note that exception 1) is handled by these routines (by constantly
  433.      * running with uid "root", while exception 2) is a serious error, and
  434.      * is not provided for at all in the switching functions.
  435.      */
  436.     if (realuid == privuid)
  437.     privuid = (UID_T) -1;        /* Not running set-user-id. */
  438.  
  439.     /* If running set-gid, go down to real gid, otherwise remember that
  440.      * no privileged gid is available.
  441.      *
  442.      * There are no exception like there is for the user id, since there
  443.      * is no group id that is privileged in the manner of uid "root".
  444.      * There could be equivalent problems for group changing if the
  445.      * program sometimes ran with uid "root" and sometimes not, but
  446.      * that is already avoided as explained above.
  447.      *
  448.      * Thus we can expect always to be able to switch to the "saved set-
  449.      * gid" when we want, and back to the real gid again. You may also
  450.      * draw the conclusion that set-gid provides for fewer hassles than
  451.      * set-uid.
  452.      */
  453.  
  454.     if (realgid == privgid)        /* If not running set-user-id, */
  455.       privgid = (GID_T) -1;        /*  remember it this way. */
  456.  
  457.     err = priv_off();            /* Turn off setuid privilege. */
  458.  
  459.     if (privuid == UID_ROOT)        /* If setuid to root, */
  460.       err |= 4;                /* return this error. */
  461.  
  462.     if (realuid == UID_ROOT)        /* If real id is root, */
  463.       privuid = (UID_T) -1;        /* stay root at all times. */
  464.  
  465.     return(err);
  466. }
  467.  
  468.  
  469. /* Macros for hiding the differences in UID/GID setting between various Unix
  470.  * systems. These macros should always be called with both the privileged ID
  471.  * and the non-privileged ID. The one in the second argument, will become the
  472.  * effective ID. The one in the first argument will be retained for later
  473.  * retrieval.
  474.  */
  475. #ifdef SETREUID
  476. #ifdef SAVEDUID
  477. /* On BSD systems with the saved-UID feature, we just juggle the effective
  478.  * UID back and forth, and leave the real UID at its true value.  The kernel
  479.  * allows switching to both the current real UID, the effective UID, and the
  480.  * UID which the program is set-UID to.  The saved set-UID always holds the
  481.  * privileged UID for us, and the real UID will always be the non-privileged,
  482.  * and we can freely choose one of them for the effective UID at any time.
  483.  */
  484. #define switchuid(hidden,active) setreuid( (UID_T) -1, active)
  485. #define switchgid(hidden,active) setregid( (GID_T) -1, active)
  486.  
  487. #else   /* SETREUID,!SAVEDUID */
  488.  
  489. /* On systems with setreXid() but without the saved-UID feature, notably
  490.  * BSD 4.2, we swap the real and effective UIDs each time.  It's
  491.  * the effective UID that we are interested in, but we have to retain the
  492.  * unused UID somewhere to enable us to restore it later, and we do this
  493.  * in the real UID.  The kernel only allows switching to either the current 
  494.  * real or the effective UID, unless you're "root".
  495.  */
  496. #define switchuid(hidden,active)    setreuid(hidden,active)
  497. #define switchgid(hidden,active)    setregid(hidden,active)
  498. #endif
  499.  
  500. #else /* !SETREUID, !SAVEDUID */
  501.  
  502. #ifdef SETEUID
  503. /*
  504.   BSD 4.4 works similarly to System V and POSIX (see below), but uses
  505.   seteXid() instead of setXid() to change effective IDs.  In addition, the
  506.   seteXid() functions work the same for "root" as for other users.
  507. */
  508. #define switchuid(hidden,active)    seteuid(active)
  509. #define switchgid(hidden,active)    setegid(active)
  510.  
  511. #else /* !SETEUID */
  512.  
  513. /* On System V and POSIX, the only thing we can change is the effective UID
  514.  * (unless the current effective UID is "root", but initsuid() avoids that for
  515.  * us).  The kernel allows switching to the current real UID or to the saved
  516.  * set-UID.  These are always set to the non-privileged UID and the privileged
  517.  * UID, respectively, and we only change the effective UID.  This breaks if
  518.  * the current effective UID is "root", though, because for "root" setuid/gid
  519.  * becomes more powerful, which is why initsuid() treats "root" specially.
  520.  * Note: That special treatment maybe could be ignored for BSD?  Note: For
  521.  * systems that don't fit any of these four cases, we simply can't support
  522.  * set-UID.
  523.  */
  524. #define switchuid(hidden,active)    setuid(active)
  525. #define switchgid(hidden,active)    setgid(active)
  526. #endif /* SETEUID */
  527. #endif /* SETREUID */
  528.   
  529.  
  530. /* P R I V _ O N  --  Turn on the setuid and/or setgid */
  531.  
  532. /* Go to the privileged uid (gid) that the program is set-user-id
  533.  * (set-group-id) to, unless the program is running unprivileged.
  534.  * If setuid() fails, return value will be 1. If getuid() fails it
  535.  * will be 2.  Return immediately after first failure, and the function
  536.  * tries to restore any partial work done.  Returns 0 on success.
  537.  * Group id is changed first, since it is less serious than user id.
  538.  */
  539. int
  540. priv_on() {
  541.     if (privgid != (GID_T) -1)
  542.       if (switchgid(realgid,privgid))
  543.         return(2);
  544.  
  545.     if (privuid != (UID_T) -1)
  546.       if (switchuid(realuid,privuid)) {
  547.       if (privgid != (GID_T) -1)
  548.         switchgid(privgid,realgid);
  549.       return(1);
  550.       }
  551.     return(0);
  552. }
  553.  
  554. /* P R I V _ O F F  --  Turn on the real uid and gid */
  555.  
  556. /* Return to the unprivileged uid (gid) after an temporary visit to
  557.  * privileged status, unless the program is running without set-user-id
  558.  * (set-group-id). Returns 1 for failure in setuid() and 2 for failure
  559.  * in setgid() or:ed together. The functions tries to return both uid
  560.  * and gid to unprivileged state, regardless of errors. Returns 0 on
  561.  * success.
  562.  */
  563. int
  564. priv_off() {
  565.     int err = 0;
  566.  
  567.     if (privuid != (UID_T) -1)
  568.        if (switchuid(privuid,realuid))
  569.       err |= 1;
  570.  
  571.     if (privgid != (GID_T) -1)
  572.        if (switchgid(privgid,realgid))
  573.     err |= 2;
  574.  
  575.     return(err);
  576. }
  577.  
  578. /* Turn off privilege permanently.  No going back.  This is necessary before
  579.  * a fork() on BSD43 machines that don't save the setUID or setGID, because
  580.  * we swap the real and effective ids, and we don't want to let the forked
  581.  * process swap them again and get the privilege back. It will work on other
  582.  * machines too, such that you can rely on its effect always being the same,
  583.  * for instance, even when you're in priv_on() state when this is called.
  584.  * (Well, that part about "permanent" is on System V only true if you follow
  585.  * this with a call to exec(), but that's what we want it for anyway.)
  586.  * Added by Dean Long -- dlong@midgard.ucsc.edu
  587.  */
  588. int
  589. priv_can() {
  590.  
  591. #ifdef SETREUID
  592.     int err = 0;
  593.     if (privuid != (UID_T) -1)
  594.        if (setreuid(realuid,realuid))
  595.       err |= 1;
  596.  
  597.     if (privgid != (GID_T) -1)
  598.         if (setregid(realgid,realgid))
  599.        err |= 2;
  600.  
  601.     return(err);
  602.  
  603. #else
  604. #ifdef SETEUID
  605.     int err = 0;
  606.     if (privuid != (UID_T) -1)
  607.        if (setuid(realuid))
  608.       err |= 1;
  609.  
  610.     if (privgid != (GID_T) -1)
  611.         if (setgid(realgid))
  612.        err |= 2;
  613.     return(err);
  614. #else
  615.     /* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
  616.     return(priv_off());
  617. #endif /* SETEUID */
  618. #endif /* SETREUID */
  619. }
  620.  
  621. /*  P R I V _ C H K  --  Check privileges.  */
  622.  
  623. /*  Try to turn them off.  If turning them off did not succeed, cancel them */
  624.  
  625. int
  626. priv_chk() {
  627.     int x, y = 0;
  628.     x = priv_off();            /* Turn off privs. */
  629.     if (x != 0 || getuid() == privuid || geteuid() == privuid)
  630.       y = priv_can();
  631.     if (x != 0 || getgid() == privgid || getegid() == privgid)
  632.       y = y | priv_can();
  633.     return(y);
  634. }
  635.  
  636. usage() {
  637.     printf("usage: %s directory\n\n", myname);
  638.     printf(
  639. "please supply the name of a directory that you have write access to.\n");
  640.     exit(1);
  641. }
  642.