chiark / gitweb /
Make guts into official library.
[checkpath] / chkpath.c
1 /* -*-c-*-
2  *
3  * $Id: chkpath.c,v 1.3 2003/01/25 23:58:44 mdw Exp $
4  *
5  * Check a user's file search path
6  *
7  * (c) 1999 Mark Wooding
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of chkpath.
13  *
14  * chkpath is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * chkpath is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with chkpath; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------* 
30  *
31  * $Log: chkpath.c,v $
32  * Revision 1.3  2003/01/25 23:58:44  mdw
33  * Make guts into official library.
34  *
35  * Revision 1.2  2001/01/25 22:16:02  mdw
36  * Make flags be unsigned.
37  *
38  * Revision 1.1.1.1  1999/04/06 20:12:07  mdw
39  * Import new project.
40  *
41  */
42
43 /*----- Header files ------------------------------------------------------*/
44
45 #include <errno.h>
46 #include <limits.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include <mLib/alloc.h>
52 #include <mLib/mdwopt.h>
53 #include <mLib/quis.h>
54 #include <mLib/report.h>
55
56 #include "checkpath.h"
57
58 /*----- Main code ---------------------------------------------------------*/
59
60 static void report(unsigned what, int verbose,
61                    const char *p, const char *msg,
62                    void *arg)
63 {
64   moan("%s", msg);
65 }
66
67 /* --- @usage@ --- */
68
69 static void usage(FILE *fp)
70 {
71   fprintf(fp, "Usage: %s [-vqstp] [PATH...]\n", QUIS);
72 }
73
74 /* --- @version@ --- */
75
76 static void version(FILE *fp)
77 {
78   fprintf(fp, "%s version %s\n", QUIS, VERSION);
79 }
80
81 /* --- @help@ --- */
82
83 static void help(FILE *fp)
84 {
85   version(fp);
86   putc('\n', fp);
87   usage(fp);
88   fputs("\n\
89 Checks a path string (by default the PATH variable) for security.  It\n\
90 ensures that only `root' or the calling user can write to all the parent\n\
91 directories of the path elements, so nobody can maliciously replace the\n\
92 binaries unexpectedly.\n\
93 \n\
94 Options provided are:\n\
95 \n\
96 -h, --help              Display this help message.\n\
97 -V, --version           Display the program's version number.\n\
98 -u, --usage             Show a terse usage summary.\n\
99 \n\
100 -v, --verbose           Be verbose about the search progress (cumulative).\n\
101 -q, --quiet             Be quiet about the search progress (cumulative).\n\
102 -s, --sticky            Consider sticky directories secure against\n\
103                         modification by world and group (not recommended).\n\
104 -t, --trust-group       Consider other members of your group trustworthy.\n\
105 -p, --print             Write the secure path elements to standard output.\n\
106 ",
107         fp);
108 }
109
110 int main(int argc, char *argv[])
111 {
112   unsigned bad = 0;
113   int i;
114   char *p, *q, *path;
115   struct checkpath cp;
116   int f = 0;
117
118 #define f_print 1u
119 #define f_colon 2u
120
121   /* --- Initialize the world --- */
122
123   ego(argv[0]);
124
125   /* --- Set up path scanning defaults --- */
126
127   cp.cp_verbose = 1;
128   cp.cp_what = CP_PROBLEMS | CP_REPORT | CP_SYMLINK;
129   cp.cp_report = report;
130   cp.cp_arg = 0;
131   checkpath_setids(&cp);
132
133   /* --- Parse the options --- */
134
135   for (;;) {
136     static struct option opts[] = {
137       { "help",         0,              0,      'h' },
138       { "version",      0,              0,      'V' },
139       { "usage",        0,              0,      'u' },
140       { "verbose",      0,              0,      'v' },
141       { "quiet",        0,              0,      'q' },
142       { "sticky",       0,              0,      's' },
143       { "trust-group",  0,              0,      't' },
144       { "print",        0,              0,      'p' },
145       { 0,              0,              0,      0 }
146     };
147     int i = mdwopt(argc, argv, "hVu vqstp", opts, 0, 0, 0);
148
149     if (i < 0)
150       break;
151     switch (i) {
152       case 'h':
153         help(stdout);
154         exit(0);
155       case 'V':
156         version(stdout);
157         exit(0);
158       case 'u':
159         usage(stdout);
160         exit(0);
161       case 'v':
162         cp.cp_verbose++;
163         break;
164       case 'q':
165         if (cp.cp_verbose)
166           cp.cp_verbose--;
167         break;
168       case 's':
169         cp.cp_what |= CP_STICKYOK;
170         break;
171       case 't':
172         cp.cp_what = (cp.cp_what & ~CP_WRGRP) | CP_WROTHGRP;
173         break;
174       case 'p':
175         f |= f_print;
176         break;
177       default:
178         bad = 1;
179         break;
180     }
181   }
182
183   if (bad) {
184     usage(stderr);
185     exit(1);
186   }
187
188   /* --- Sort out what needs doing --- */
189
190   if (optind == argc) {
191     path = getenv("PATH");
192     argv = &path;
193     argc = 1;
194     optind = 0;
195   }
196
197   for (i = optind; i < argc; i++) {
198     p = xstrdup(argv[i]);
199     q = strtok(p, ":");
200     while (q) {
201       unsigned b = checkpath(q, &cp);
202       if (!b && (f & f_print)) {
203         if (f & f_colon)
204           putchar(':');
205         fputs(q, stdout);
206         f |= f_colon;
207       }
208       bad |= b;
209       q = strtok(0, ":");
210     }
211     free(p);
212   }
213
214   if (f & f_colon)
215     putchar('\n');
216
217   return (bad);
218 }
219
220 /*----- That's all, folks -------------------------------------------------*/