pcnfsd_v2.c revision 1.10
1/*	$NetBSD: pcnfsd_v2.c,v 1.10 2009/04/18 13:02:36 lukem 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
60static char no_comment[] = "No comment";
61static char not_supported[] = "Not supported";
62static char pcnfsd_version[] = "@(#)pcnfsd_v2.c	1.2 - rpc.pcnfsd V2.0 (c) 1991 Sun Technology Enterprises, Inc.";
63
64/*ARGSUSED*/
65void   *
66pcnfsd2_null_2_svc(arg, req)
67	void   *arg;
68	struct svc_req *req;
69{
70	static char dummy;
71	return ((void *) &dummy);
72}
73
74v2_auth_results *
75pcnfsd2_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			strlcpy(home, yphome, sizeof(home));
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		strlcpy(home, yphome, sizeof(home));
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
170v2_pr_init_results *
171pcnfsd2_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
185v2_pr_start_results *
186pcnfsd2_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*/
200v2_pr_list_results *
201pcnfsd2_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
215v2_pr_queue_results *
216pcnfsd2_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
232v2_pr_status_results *
233pcnfsd2_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
248v2_pr_cancel_results *
249pcnfsd2_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*/
261v2_pr_requeue_results *
262pcnfsd2_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*/
273v2_pr_hold_results *
274pcnfsd2_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*/
286v2_pr_release_results *
287pcnfsd2_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*/
299v2_pr_admin_results *
300pcnfsd2_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
318void
319free_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
330static char *my_strdup __P((const char *));
331
332static char *
333my_strdup(s)
334	const char   *s;
335{
336	char   *r;
337	r = (char *) grab(strlen(s) + 1);
338	strlcpy(r, s, strlen(s) + 1);
339	return (r);
340}
341
342v2_mapid_results *
343pcnfsd2_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*/
419v2_alert_results *
420pcnfsd2_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*/
432v2_info_results *
433pcnfsd2_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
474void
475fillin_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 */
513char   *
514find_entry(key, map)
515	const char   *key;
516	const 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