xref: /plan9-contrib/sys/src/cmd/9nfs/unixnames.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include "all.h"
2 
3 static void	uxfree(Unixid*);
4 
5 static Unixid *	xfree;
6 
7 Unixidmap *idhead, *idtail;
8 
9 Unixscmap *scmap;
10 
11 #define	UNUSED	0x7FFFFFFF
12 
13 /*
14  * Sadly we have to use the IP address, since some systems (FreeBSD in particular)
15  * do not believe it to be safe to depend on the hostname and so refuse to send it.
16  * I dislike making this IP-centric, but so be it.
17  * We keep a cache of host names in getdom.
18  */
19 Unixidmap *
20 pair2idmap(char *server, ulong clientip)
21 {
22 	Resub match;
23 	Unixscmap *m, *mp;
24 	Unixidmap *r;
25 	char dom[256];
26 
27 	for(mp=0,m=scmap; m; mp=m,m=m->next){
28 		if(m->server[0] != server[0])
29 			continue;
30 		if(strcmp(m->server, server))
31 			continue;
32 		if(m->clientip != clientip)
33 			continue;
34 		if(mp){
35 			mp->next = m->next;
36 			m->next = scmap;
37 			scmap = m;
38 		}
39 		r = m->map;
40 		if(r->u.timestamp != 0 && r->g.timestamp != 0)
41 			return r;
42 		scmap = m->next;
43 		free(m);
44 		break;
45 	}
46 fprint(2, "looking for %lux\n", clientip);
47 	if(getdom(clientip, dom, sizeof dom)<0){
48 		clog("auth: unknown ip address");
49 		return nil;
50 	}
51 fprint(2, "dom is %s\n", dom);
52 	for(r=idhead; r; r=r->next){
53 		if(r->u.timestamp == 0 || r->g.timestamp == 0)
54 			continue;
55 		match.sp = match.ep = 0;
56 		if(regexec(r->sexp, server, &match, 1) == 0)
57 			continue;
58 		if(match.sp != server || match.ep <= match.sp || *match.ep)
59 			continue;
60 		match.sp = match.ep = 0;
61 		if(regexec(r->cexp, dom, &match, 1) == 0)
62 			continue;
63 		if(match.sp != dom || match.ep <= match.sp || *match.ep)
64 			continue;
65 		m = malloc(sizeof(Unixscmap));
66 		m->next = scmap;
67 		scmap = m;
68 		m->server = strstore(server);
69 		m->clientip = clientip;
70 		m->map = r;
71 		break;
72 	}
73 	return r;
74 }
75 
76 int
77 readunixidmaps(char *file)
78 {
79 	Waitmsg *w;
80 	Biobuf *in;
81 	Unixidmap *m;
82 	int i, arc; char *arv[16], buf[256];
83 	char *l;
84 	long savalarm;
85 
86 	savalarm = alarm(0);
87 	in = Bopen(file, OREAD);
88 	if(in == 0){
89 		clog("readunixidmaps can't open %s: %r\n", file);
90 		alarm(savalarm);
91 		return -1;
92 	}
93 	for(m=idhead; m; m=m->next)
94 		m->flag = 0;
95 	while(l = Brdline(in, '\n')){	/* assign = */
96 		l[Blinelen(in)-1] = 0;
97 		arc = strparse(l, nelem(arv), arv);
98 		if(arc > 0 && arv[0][0] == '!'){
99 			++arv[0];
100 			snprint(buf, sizeof buf, "/bin/%s", arv[0]);
101 			if(chatty){
102 				chat("!");
103 				for(i=0; i<arc; i++)
104 					chat(" %s", arv[i]);
105 				chat("...");
106 			}
107 			w = system(buf, arv);
108 			if(w == nil)
109 				chat("err: %r\n");
110 			else if(w->msg && w->msg[0])
111 				chat("status: %s\n", w->msg);
112 			else
113 				chat("OK\n");
114 			free(w);
115 			continue;
116 		}
117 		if(arc != 4)
118 			continue;
119 		for(m=idhead; m; m=m->next)
120 			if(strcmp(arv[0], m->server) == 0 &&
121 			   strcmp(arv[1], m->client) == 0)
122 				break;
123 		if(m == 0){
124 			m = malloc(sizeof(Unixidmap));
125 			if(idtail)
126 				idtail->next = m;
127 			else
128 				idhead = m;
129 			idtail = m;
130 			m->next = 0;
131 			m->server = strstore(arv[0]);
132 			m->client = strstore(arv[1]);
133 			m->sexp = regcomp(m->server);
134 			m->cexp = regcomp(m->client);
135 			m->u.file = strstore(arv[2]);
136 			m->u.style = 'u';
137 			m->u.timestamp = 0;
138 			m->u.ids = 0;
139 			m->g.file = strstore(arv[3]);
140 			m->g.style = 'u';
141 			m->g.timestamp = 0;
142 			m->g.ids = 0;
143 		}else{
144 			if(!m->u.file || strcmp(m->u.file, arv[2]) != 0){
145 				m->u.file = strstore(arv[2]);
146 				m->u.timestamp = 0;
147 			}
148 			if(!m->g.file || strcmp(m->g.file, arv[3]) != 0){
149 				m->g.file = strstore(arv[3]);
150 				m->g.timestamp = 0;
151 			}
152 		}
153 		m->flag = 1;
154 		checkunixmap(&m->u);
155 		checkunixmap(&m->g);
156 	}
157 	Bterm(in);
158 	for(m=idhead; m; m=m->next)
159 		if(m->flag == 0){
160 			m->u.file = 0;
161 			m->u.timestamp = 0;
162 			uxfree(m->u.ids);
163 			m->u.ids = 0;
164 			m->g.file = 0;
165 			m->g.timestamp = 0;
166 			uxfree(m->g.ids);
167 			m->g.ids = 0;
168 		}
169 	alarm(savalarm);
170 	return 0;
171 }
172 
173 static void
174 uxfree(Unixid *x)
175 {
176 	Unixid *tail;
177 	int count=0;
178 
179 	if(x){
180 		tail = x;
181 		if(tail->id < 0)
182 			abort();
183 		tail->id = UNUSED;
184 		while(tail->next){
185 			tail = tail->next;
186 			++count;
187 			if(tail->id == UNUSED)
188 				abort();
189 			tail->id = UNUSED;
190 		}
191 		tail->next = xfree;
192 		xfree = x;
193 	}
194 }
195 
196 int
197 checkunixmap(Unixmap *u)
198 {
199 	Dir *dir;
200 
201 	dir = dirstat(u->file);
202 	if(dir == nil){
203 		clog("checkunixmap can't stat %s: %r\n", u->file);
204 		return -1;
205 	}
206 	if(u->timestamp > dir->mtime){
207 		free(dir);
208 		return 0;
209 	}
210 	uxfree(u->ids);
211 	u->ids = readunixids(u->file, u->style);
212 	u->timestamp = time(0);
213 	free(dir);
214 	return 1;
215 }
216 
217 int
218 name2id(Unixid **list, char *name)
219 {
220 	Unixid *x, *xp;
221 
222 	for(xp=0,x=*list; x; xp=x,x=x->next){
223 		if(x->name[0] == name[0] && strcmp(x->name, name) == 0){
224 			if(xp){
225 				xp->next = x->next;
226 				x->next = *list;
227 				*list = x;
228 			}
229 			return x->id;
230 		}
231 	}
232 	return -1;
233 }
234 
235 char *
236 id2name(Unixid **list, int id)
237 {
238 	Unixid *x, *xp;
239 
240 	for(xp=0,x=*list; x; xp=x,x=x->next){
241 		if(x->id == id){
242 			if(xp){
243 				xp->next = x->next;
244 				x->next = *list;
245 				*list = x;
246 			}
247 			return x->name;
248 		}
249 	}
250 	return "none";
251 }
252 
253 void
254 idprint(int fd, Unixid *xp)
255 {
256 	while(xp){
257 		fprint(fd, "%d\t%s\n", xp->id, xp->name);
258 		xp = xp->next;
259 	}
260 }
261 
262 /*
263  *	style '9': 3:tom:tom:
264  *	style 'u': sysadm:*:0:0:System-Administrator:/usr/admin:/bin/sh
265  */
266 
267 Unixid *
268 readunixids(char *file, int style)
269 {
270 	Biobuf *in;
271 	char *l, *name = 0;
272 	Unixid *x, *xp = 0;
273 	int id = 0;
274 
275 	in = Bopen(file, OREAD);
276 	if(in == 0){
277 		clog("readunixids can't open %s: %r\n", file);
278 		return 0;
279 	}
280 	while(l = Brdline(in, '\n')){	/* assign = */
281 		l[Blinelen(in)-1] = 0;
282 		switch(style){
283 		case '9':
284 			id = strtol(l, &l, 10);
285 			if(*l != ':')
286 				continue;
287 			name = ++l;
288 			l = strchr(l, ':');
289 			if(l == 0)
290 				continue;
291 			*l = 0;
292 			break;
293 		case 'u':
294 			name = l;
295 			l = strchr(l, ':');
296 			if(l == 0)
297 				continue;
298 			*l++ = 0;
299 			/* skip password */
300 			l = strchr(l, ':');
301 			if(l == 0)
302 				continue;
303 			id = strtol(l+1, 0, 10);
304 			break;
305 		default:
306 			panic("unknown unixid style %d\n", style);
307 		}
308 		if(id == UNUSED)
309 			id = -1;	/* any value will do */
310 		if(!(x = xfree))	/* assign = */
311 			x = listalloc(1024/sizeof(Unixid), sizeof(Unixid));
312 		xfree = x->next;
313 		x->id = id;
314 		x->name = strstore(name);
315 		x->next = xp;
316 		xp = x;
317 	}
318 	Bterm(in);
319 	return xp;
320 }
321