xref: /netbsd/usr.sbin/rpc.pcnfsd/pcnfsd_v2.c (revision bf9ec67e)
1 /*	$NetBSD: pcnfsd_v2.c,v 1.8 1998/07/27 15:14:05 mycroft Exp $	*/
2 
3 /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_v2.c 1.2 91/12/18 13:26:13 SMI */
4 /*
5 **=====================================================================
6 ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
7 **	@(#)pcnfsd_v2.c	1.2	12/18/91
8 **=====================================================================
9 */
10 /*
11 **=====================================================================
12 **             I N C L U D E   F I L E   S E C T I O N                *
13 **                                                                    *
14 ** If your port requires different include files, add a suitable      *
15 ** #define in the customization section, and make the inclusion or    *
16 ** exclusion of the files conditional on this.                        *
17 **=====================================================================
18 */
19 
20 #include <sys/file.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 
24 #include <grp.h>
25 #include <netdb.h>
26 #include <pwd.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #ifdef USE_YP
34 #include <rpcsvc/ypclnt.h>
35 #endif
36 
37 #ifndef SYSV
38 #include <sys/wait.h>
39 #endif
40 
41 #ifdef ISC_2_0
42 #include <sys/fcntl.h>
43 #endif
44 
45 #ifdef SHADOW_SUPPORT
46 #include <shadow.h>
47 #endif
48 
49 #include "common.h"
50 #include "pcnfsd.h"
51 #include "extern.h"
52 
53 /*
54 **=====================================================================
55 **                      C O D E   S E C T I O N                       *
56 **=====================================================================
57 */
58 
59 
60 static char no_comment[] = "No comment";
61 static char not_supported[] = "Not supported";
62 static char pcnfsd_version[] = "@(#)pcnfsd_v2.c	1.2 - rpc.pcnfsd V2.0 (c) 1991 Sun Technology Enterprises, Inc.";
63 
64 /*ARGSUSED*/
65 void   *
66 pcnfsd2_null_2_svc(arg, req)
67 	void   *arg;
68 	struct svc_req *req;
69 {
70 	static char dummy;
71 	return ((void *) &dummy);
72 }
73 
74 v2_auth_results *
75 pcnfsd2_auth_2_svc(arg, req)
76 	v2_auth_args *arg;
77 	struct svc_req *req;
78 {
79 	static v2_auth_results r;
80 
81 	char    uname[32];
82 	char    pw[64];
83 	int     c1, c2;
84 	struct passwd *p;
85 	static u_int extra_gids[EXTRAGIDLEN];
86 	static char home[256];
87 #ifdef USE_YP
88 	char   *yphome;
89 	char   *cp;
90 #endif				/* USE_YP */
91 
92 
93 	r.stat = AUTH_RES_FAIL;	/* assume failure */
94 	r.uid = (int) -2;
95 	r.gid = (int) -2;
96 	r.cm = &no_comment[0];
97 	r.gids.gids_len = 0;
98 	r.gids.gids_val = &extra_gids[0];
99 	home[0] = '\0';
100 	r.home = &home[0];
101 	r.def_umask = umask(0);
102 	(void) umask(r.def_umask);	/* or use 022 */
103 
104 	scramble(arg->id, uname);
105 	scramble(arg->pw, pw);
106 
107 #ifdef USER_CACHE
108 	if (check_cache(uname, pw, &r.uid, &r.gid)) {
109 		r.stat = AUTH_RES_OK;
110 #ifdef WTMP
111 		wlogin(uname, req);
112 #endif
113 		fillin_extra_groups
114 		    (uname, r.gid, &r.gids.gids_len, extra_gids);
115 #ifdef USE_YP
116 		yphome = find_entry(uname, "auto.home");
117 		if (yphome) {
118 			strcpy(home, yphome);
119 			free(yphome);
120 			cp = strchr(home, ':');
121 			cp++;
122 			cp = strchr(cp, ':');
123 			if (cp)
124 				*cp = '/';
125 		}
126 #endif
127 		return (&r);
128 	}
129 #endif
130 
131 	p = get_password(uname);
132 	if (p == (struct passwd *) NULL)
133 		return (&r);
134 
135 	c1 = strlen(pw);
136 	c2 = strlen(p->pw_passwd);
137 	if ((c1 && !c2) || (c2 && !c1) ||
138 	    (strcmp(p->pw_passwd, crypt(pw, p->pw_passwd)))) {
139 		return (&r);
140 	}
141 	r.stat = AUTH_RES_OK;
142 	r.uid = p->pw_uid;
143 	r.gid = p->pw_gid;
144 #ifdef WTMP
145 	wlogin(uname, req);
146 #endif
147 	fillin_extra_groups(uname, r.gid, &r.gids.gids_len, extra_gids);
148 
149 #ifdef USE_YP
150 	yphome = find_entry(uname, "auto.home");
151 	if (yphome) {
152 		strcpy(home, yphome);
153 		free(yphome);
154 		cp = strchr(home, ':');
155 		cp++;
156 		cp = strchr(cp, ':');
157 		if (cp)
158 			*cp = '/';
159 	}
160 #endif
161 
162 #ifdef USER_CACHE
163 	add_cache_entry(p);
164 #endif
165 
166 	return (&r);
167 
168 }
169 
170 v2_pr_init_results *
171 pcnfsd2_pr_init_2_svc(arg, req)
172 	v2_pr_init_args *arg;
173 	struct svc_req *req;
174 {
175 	static v2_pr_init_results res;
176 
177 	res.stat =
178 	    (pirstat) pr_init(arg->system, arg->pn, &res.dir);
179 	res.cm = &no_comment[0];
180 
181 
182 	return (&res);
183 }
184 
185 v2_pr_start_results *
186 pcnfsd2_pr_start_2_svc(arg, req)
187 	v2_pr_start_args *arg;
188 	struct svc_req *req;
189 {
190 	static v2_pr_start_results res;
191 
192 	res.stat =
193 	    (psrstat) pr_start2(arg->system, arg->pn, arg->user,
194 	    arg->file, arg->opts, &res.id);
195 	res.cm = &no_comment[0];
196 
197 	return (&res);
198 }
199 /*ARGSUSED*/
200 v2_pr_list_results *
201 pcnfsd2_pr_list_2_svc(arg, req)
202 	void   *arg;
203 	struct svc_req *req;
204 {
205 	static v2_pr_list_results res;
206 
207 	if (printers == NULL)
208 		(void) build_pr_list();
209 	res.cm = &no_comment[0];
210 	res.printers = printers;
211 
212 	return (&res);
213 }
214 
215 v2_pr_queue_results *
216 pcnfsd2_pr_queue_2_svc(arg, req)
217 	v2_pr_queue_args *arg;
218 	struct svc_req *req;
219 {
220 	static v2_pr_queue_results res;
221 
222 	res.stat = build_pr_queue(arg->pn, arg->user,
223 	    arg->just_mine, &res.qlen, &res.qshown);
224 	res.cm = &no_comment[0];
225 	res.just_yours = arg->just_mine;
226 	res.jobs = queue;
227 
228 
229 	return (&res);
230 }
231 
232 v2_pr_status_results *
233 pcnfsd2_pr_status_2_svc(arg, req)
234 	v2_pr_status_args *arg;
235 	struct svc_req *req;
236 {
237 	static v2_pr_status_results res;
238 	static char status[128];
239 
240 	res.stat = get_pr_status(arg->pn, &res.avail, &res.printing,
241 	    &res.qlen, &res.needs_operator, &status[0]);
242 	res.status = &status[0];
243 	res.cm = &no_comment[0];
244 
245 	return (&res);
246 }
247 
248 v2_pr_cancel_results *
249 pcnfsd2_pr_cancel_2_svc(arg, req)
250 	v2_pr_cancel_args *arg;
251 	struct svc_req *req;
252 {
253 	static v2_pr_cancel_results res;
254 
255 	res.stat = pr_cancel(arg->pn, arg->user, arg->id);
256 	res.cm = &no_comment[0];
257 
258 	return (&res);
259 }
260 /*ARGSUSED*/
261 v2_pr_requeue_results *
262 pcnfsd2_pr_requeue_2_svc(arg, req)
263 	v2_pr_requeue_args *arg;
264 	struct svc_req *req;
265 {
266 	static v2_pr_requeue_results res;
267 	res.stat = PC_RES_FAIL;
268 	res.cm = &not_supported[0];
269 
270 	return (&res);
271 }
272 /*ARGSUSED*/
273 v2_pr_hold_results *
274 pcnfsd2_pr_hold_2_svc(arg, req)
275 	v2_pr_hold_args *arg;
276 	struct svc_req *req;
277 {
278 	static v2_pr_hold_results res;
279 
280 	res.stat = PC_RES_FAIL;
281 	res.cm = &not_supported[0];
282 
283 	return (&res);
284 }
285 /*ARGSUSED*/
286 v2_pr_release_results *
287 pcnfsd2_pr_release_2_svc(arg, req)
288 	v2_pr_release_args *arg;
289 	struct svc_req *req;
290 {
291 	static v2_pr_release_results res;
292 
293 	res.stat = PC_RES_FAIL;
294 	res.cm = &not_supported[0];
295 
296 	return (&res);
297 }
298 /*ARGSUSED*/
299 v2_pr_admin_results *
300 pcnfsd2_pr_admin_2_svc(arg, req)
301 	v2_pr_admin_args *arg;
302 	struct svc_req *req;
303 {
304 	static v2_pr_admin_results res;
305 /*
306 ** The default action for admin is to fail.
307 ** If someone wishes to implement an administration
308 ** mechanism, and isn't worried about the security
309 ** holes, go right ahead.
310 */
311 
312 	res.cm = &not_supported[0];
313 	res.stat = PI_RES_FAIL;
314 
315 	return (&res);
316 }
317 
318 void
319 free_mapreq_results(p)
320 	mapreq_res p;
321 {
322 	if (p->mapreq_next)
323 		free_mapreq_results(p->mapreq_next);	/* recurse */
324 	if (p->name)
325 		(void) free(p->name);
326 	(void) free(p);
327 	return;
328 }
329 
330 static char *my_strdup __P((const char *));
331 
332 static char *
333 my_strdup(s)
334 	const char   *s;
335 {
336 	char   *r;
337 	r = (char *) grab(strlen(s) + 1);
338 	strcpy(r, s);
339 	return (r);
340 }
341 
342 v2_mapid_results *
343 pcnfsd2_mapid_2_svc(arg, req)
344 	v2_mapid_args *arg;
345 	struct svc_req *req;
346 {
347 	static v2_mapid_results res;
348 	struct passwd *p_passwd;
349 	struct group *p_group;
350 
351 	mapreq_arg a;
352 	mapreq_res next_r;
353 	mapreq_res last_r = NULL;
354 
355 
356 	if (res.res_list) {
357 		free_mapreq_results(res.res_list);
358 		res.res_list = NULL;
359 	}
360 	a = arg->req_list;
361 	while (a) {
362 		next_r = (struct mapreq_res_item *)
363 		    grab(sizeof(struct mapreq_res_item));
364 		next_r->stat = MAP_RES_UNKNOWN;
365 		next_r->req = a->req;
366 		next_r->id = a->id;
367 		next_r->name = NULL;
368 		next_r->mapreq_next = NULL;
369 
370 		if (last_r == NULL)
371 			res.res_list = next_r;
372 		else
373 			last_r->mapreq_next = next_r;
374 		last_r = next_r;
375 		switch (a->req) {
376 		case MAP_REQ_UID:
377 			p_passwd = getpwuid((uid_t) a->id);
378 			if (p_passwd) {
379 				next_r->name = my_strdup(p_passwd->pw_name);
380 				next_r->stat = MAP_RES_OK;
381 			}
382 			break;
383 		case MAP_REQ_GID:
384 			p_group = getgrgid((gid_t) a->id);
385 			if (p_group) {
386 				next_r->name = my_strdup(p_group->gr_name);
387 				next_r->stat = MAP_RES_OK;
388 			}
389 			break;
390 		case MAP_REQ_UNAME:
391 			next_r->name = my_strdup(a->name);
392 			p_passwd = getpwnam(a->name);
393 			if (p_passwd) {
394 				next_r->id = p_passwd->pw_uid;
395 				next_r->stat = MAP_RES_OK;
396 			}
397 			break;
398 		case MAP_REQ_GNAME:
399 			next_r->name = my_strdup(a->name);
400 			p_group = getgrnam(a->name);
401 			if (p_group) {
402 				next_r->id = p_group->gr_gid;
403 				next_r->stat = MAP_RES_OK;
404 			}
405 			break;
406 		}
407 		if (next_r->name == NULL)
408 			next_r->name = my_strdup("");
409 		a = a->mapreq_next;
410 	}
411 
412 	res.cm = &no_comment[0];
413 
414 	return (&res);
415 }
416 
417 
418 /*ARGSUSED*/
419 v2_alert_results *
420 pcnfsd2_alert_2_svc(arg, req)
421 	v2_alert_args *arg;
422 	struct svc_req *req;
423 {
424 	static v2_alert_results res;
425 
426 	res.stat = ALERT_RES_FAIL;
427 	res.cm = &not_supported[0];
428 
429 	return (&res);
430 }
431 /*ARGSUSED*/
432 v2_info_results *
433 pcnfsd2_info_2_svc(arg, req)
434 	v2_info_args *arg;
435 	struct svc_req *req;
436 {
437 	static v2_info_results res;
438 	static int facilities[FACILITIESMAX];
439 	static int onetime = 1;
440 
441 #define UNSUPPORTED -1
442 #define QUICK 100
443 #define SLOW 2000
444 
445 	if (onetime) {
446 		onetime = 0;
447 		facilities[PCNFSD2_NULL] = QUICK;
448 		facilities[PCNFSD2_INFO] = QUICK;
449 		facilities[PCNFSD2_PR_INIT] = QUICK;
450 		facilities[PCNFSD2_PR_START] = SLOW;
451 		facilities[PCNFSD2_PR_LIST] = QUICK;	/* except first time */
452 		facilities[PCNFSD2_PR_QUEUE] = SLOW;
453 		facilities[PCNFSD2_PR_STATUS] = SLOW;
454 		facilities[PCNFSD2_PR_CANCEL] = SLOW;
455 		facilities[PCNFSD2_PR_ADMIN] = UNSUPPORTED;
456 		facilities[PCNFSD2_PR_REQUEUE] = UNSUPPORTED;
457 		facilities[PCNFSD2_PR_HOLD] = UNSUPPORTED;
458 		facilities[PCNFSD2_PR_RELEASE] = UNSUPPORTED;
459 		facilities[PCNFSD2_MAPID] = QUICK;
460 		facilities[PCNFSD2_AUTH] = QUICK;
461 		facilities[PCNFSD2_ALERT] = QUICK;
462 	}
463 	res.facilities.facilities_len = PCNFSD2_ALERT + 1;
464 	res.facilities.facilities_val = facilities;
465 
466 	res.vers = &pcnfsd_version[0];
467 	res.cm = &no_comment[0];
468 
469 	return (&res);
470 }
471 
472 
473 
474 void
475 fillin_extra_groups(uname, main_gid, len, extra_gids)
476 	char   *uname;
477 	gid_t   main_gid;
478 	int    *len;
479 	gid_t   extra_gids[EXTRAGIDLEN];
480 {
481 	struct group *grp;
482 	__aconst char *__aconst *members;
483 	int     n = 0;
484 
485 	setgrent();
486 
487 	while (n < EXTRAGIDLEN) {
488 		grp = getgrent();
489 		if (grp == NULL)
490 			break;
491 		if (grp->gr_gid == main_gid)
492 			continue;
493 		for (members = grp->gr_mem; members && *members; members++) {
494 			if (!strcmp(*members, uname)) {
495 				extra_gids[n++] = grp->gr_gid;
496 				break;
497 			}
498 		}
499 	}
500 	endgrent();
501 	*len = n;
502 }
503 
504 #ifdef USE_YP
505 /* the following is from rpcsvc/yp_prot.h */
506 #define YPMAXDOMAIN 64
507 
508 /*
509  * find_entry returns NULL on any error (printing a message) and
510  * otherwise returns a pointer to the malloc'd result. The caller
511  * is responsible for free()ing the result string.
512  */
513 char   *
514 find_entry(key, map)
515 	char   *key;
516 	char   *map;
517 {
518 	int     err;
519 	char   *val = NULL;
520 	char   *cp;
521 	int     len = 0;
522 	static char domain[YPMAXDOMAIN + 1];
523 
524 	if (getdomainname(domain, YPMAXDOMAIN)) {
525 		msg_out("rpc.pcnfsd: getdomainname failed");
526 		return (NULL);
527 	}
528 	if ((err = yp_bind(domain)) != 0) {
529 #ifdef	DEBUG
530 		msg_out("rpc.pcnfsd: yp_bind failed");
531 #endif
532 		return (NULL);
533 	}
534 	err = yp_match(domain, map, key, strlen(key), &val, &len);
535 
536 	if (err) {
537 		msg_out("rpc.pcnfsd: yp_match failed");
538 		if (val)
539 			free(val);
540 		return (NULL);
541 	}
542 	if ((cp = strchr(val, '\n')) != NULL)
543 		*cp = '\0';	/* in case we get an extra NL at the end */
544 	return (val);
545 }
546 #endif
547