1/*	$NetBSD: pcnfsd_v2.c,v 1.14 2018/01/23 21:06:25 sevan 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(void *arg, struct svc_req *req)
67{
68	static char dummy;
69	return ((void *) &dummy);
70}
71
72v2_auth_results *
73pcnfsd2_auth_2_svc(v2_auth_args *arg, struct svc_req *req)
74{
75	static v2_auth_results r;
76
77	char    uname[32];
78	char    pw[64];
79	int     c1, c2;
80	struct passwd *p;
81	static u_int extra_gids[EXTRAGIDLEN];
82	static char home[256];
83#ifdef USE_YP
84	char   *yphome;
85	char   *cp;
86#endif				/* USE_YP */
87
88
89	r.stat = AUTH_RES_FAIL;	/* assume failure */
90	r.uid = (int) -2;
91	r.gid = (int) -2;
92	r.cm = &no_comment[0];
93	r.gids.gids_len = 0;
94	r.gids.gids_val = &extra_gids[0];
95	home[0] = '\0';
96	r.home = &home[0];
97	r.def_umask = umask(0);
98	(void) umask(r.def_umask);	/* or use 022 */
99
100	scramble(arg->id, uname);
101	scramble(arg->pw, pw);
102
103#ifdef USER_CACHE
104	if (check_cache(uname, pw, &r.uid, &r.gid)) {
105		r.stat = AUTH_RES_OK;
106#ifdef WTMP
107		wlogin(uname, req);
108#endif
109		fillin_extra_groups
110		    (uname, r.gid, &r.gids.gids_len, extra_gids);
111#ifdef USE_YP
112		yphome = find_entry(uname, "auto.home");
113		if (yphome) {
114			strlcpy(home, yphome, sizeof(home));
115			free(yphome);
116			cp = strchr(home, ':');
117			cp++;
118			cp = strchr(cp, ':');
119			if (cp)
120				*cp = '/';
121		}
122#endif
123		return (&r);
124	}
125#endif
126
127	p = get_password(uname);
128	if (p == NULL)
129		return (&r);
130
131	c1 = strlen(pw);
132	c2 = strlen(p->pw_passwd);
133	if ((c1 && !c2) || (c2 && !c1) ||
134	    (strcmp(p->pw_passwd, crypt(pw, p->pw_passwd)))) {
135		return (&r);
136	}
137	r.stat = AUTH_RES_OK;
138	r.uid = p->pw_uid;
139	r.gid = p->pw_gid;
140#ifdef WTMP
141	wlogin(uname, req);
142#endif
143	fillin_extra_groups(uname, r.gid, &r.gids.gids_len, extra_gids);
144
145#ifdef USE_YP
146	yphome = find_entry(uname, "auto.home");
147	if (yphome) {
148		strlcpy(home, yphome, sizeof(home));
149		free(yphome);
150		cp = strchr(home, ':');
151		cp++;
152		cp = strchr(cp, ':');
153		if (cp)
154			*cp = '/';
155	}
156#endif
157
158#ifdef USER_CACHE
159	add_cache_entry(p);
160#endif
161
162	return (&r);
163
164}
165
166v2_pr_init_results *
167pcnfsd2_pr_init_2_svc(v2_pr_init_args *arg, struct svc_req *req)
168{
169	static v2_pr_init_results res;
170
171	res.stat =
172	    (pirstat) pr_init(arg->system, arg->pn, &res.dir);
173	res.cm = &no_comment[0];
174
175
176	return (&res);
177}
178
179v2_pr_start_results *
180pcnfsd2_pr_start_2_svc(v2_pr_start_args *arg, struct svc_req *req)
181{
182	static v2_pr_start_results res;
183
184	res.stat =
185	    (psrstat) pr_start2(arg->system, arg->pn, arg->user,
186	    arg->file, arg->opts, &res.id);
187	res.cm = &no_comment[0];
188
189	return (&res);
190}
191/*ARGSUSED*/
192v2_pr_list_results *
193pcnfsd2_pr_list_2_svc(void *arg, struct svc_req *req)
194{
195	static v2_pr_list_results res;
196
197	if (printers == NULL)
198		(void) build_pr_list();
199	res.cm = &no_comment[0];
200	res.printers = printers;
201
202	return (&res);
203}
204
205v2_pr_queue_results *
206pcnfsd2_pr_queue_2_svc(v2_pr_queue_args *arg, struct svc_req *req)
207{
208	static v2_pr_queue_results res;
209
210	res.stat = build_pr_queue(arg->pn, arg->user,
211	    arg->just_mine, &res.qlen, &res.qshown);
212	res.cm = &no_comment[0];
213	res.just_yours = arg->just_mine;
214	res.jobs = queue;
215
216
217	return (&res);
218}
219
220v2_pr_status_results *
221pcnfsd2_pr_status_2_svc(v2_pr_status_args *arg, struct svc_req *req)
222{
223	static v2_pr_status_results res;
224	static char status[128];
225
226	res.stat = get_pr_status(arg->pn, &res.avail, &res.printing,
227	    &res.qlen, &res.needs_operator, &status[0], sizeof(status));
228	res.status = &status[0];
229	res.cm = &no_comment[0];
230
231	return (&res);
232}
233
234v2_pr_cancel_results *
235pcnfsd2_pr_cancel_2_svc(v2_pr_cancel_args *arg, struct svc_req *req)
236{
237	static v2_pr_cancel_results res;
238
239	res.stat = pr_cancel(arg->pn, arg->user, arg->id);
240	res.cm = &no_comment[0];
241
242	return (&res);
243}
244/*ARGSUSED*/
245v2_pr_requeue_results *
246pcnfsd2_pr_requeue_2_svc(v2_pr_requeue_args *arg, struct svc_req *req)
247{
248	static v2_pr_requeue_results res;
249	res.stat = PC_RES_FAIL;
250	res.cm = &not_supported[0];
251
252	return (&res);
253}
254/*ARGSUSED*/
255v2_pr_hold_results *
256pcnfsd2_pr_hold_2_svc(v2_pr_hold_args *arg, struct svc_req *req)
257{
258	static v2_pr_hold_results res;
259
260	res.stat = PC_RES_FAIL;
261	res.cm = &not_supported[0];
262
263	return (&res);
264}
265/*ARGSUSED*/
266v2_pr_release_results *
267pcnfsd2_pr_release_2_svc(v2_pr_release_args *arg, struct svc_req *req)
268{
269	static v2_pr_release_results res;
270
271	res.stat = PC_RES_FAIL;
272	res.cm = &not_supported[0];
273
274	return (&res);
275}
276/*ARGSUSED*/
277v2_pr_admin_results *
278pcnfsd2_pr_admin_2_svc(v2_pr_admin_args *arg, struct svc_req *req)
279{
280	static v2_pr_admin_results res;
281/*
282** The default action for admin is to fail.
283** If someone wishes to implement an administration
284** mechanism, and isn't worried about the security
285** holes, go right ahead.
286*/
287
288	res.cm = &not_supported[0];
289	res.stat = PI_RES_FAIL;
290
291	return (&res);
292}
293
294void
295free_mapreq_results(mapreq_res p)
296{
297	if (p->mapreq_next)
298		free_mapreq_results(p->mapreq_next);	/* recurse */
299	if (p->name)
300		(void) free(p->name);
301	(void) free(p);
302	return;
303}
304
305static char *my_strdup(const char *);
306
307static char *
308my_strdup(const char *s)
309{
310	size_t len;
311	char   *r;
312	len = strlen(s);
313	r = (char *) grab(len + 1);
314	memcpy(r, s, len + 1);
315	return (r);
316}
317
318v2_mapid_results *
319pcnfsd2_mapid_2_svc(v2_mapid_args *arg, struct svc_req *req)
320{
321	static v2_mapid_results res;
322	struct passwd *p_passwd;
323	struct group *p_group;
324
325	mapreq_arg a;
326	mapreq_res next_r;
327	mapreq_res last_r = NULL;
328
329
330	if (res.res_list) {
331		free_mapreq_results(res.res_list);
332		res.res_list = NULL;
333	}
334	a = arg->req_list;
335	while (a) {
336		next_r = (struct mapreq_res_item *)
337		    grab(sizeof(struct mapreq_res_item));
338		next_r->stat = MAP_RES_UNKNOWN;
339		next_r->req = a->req;
340		next_r->id = a->id;
341		next_r->name = NULL;
342		next_r->mapreq_next = NULL;
343
344		if (last_r == NULL)
345			res.res_list = next_r;
346		else
347			last_r->mapreq_next = next_r;
348		last_r = next_r;
349		switch (a->req) {
350		case MAP_REQ_UID:
351			p_passwd = getpwuid((uid_t) a->id);
352			if (p_passwd) {
353				next_r->name = my_strdup(p_passwd->pw_name);
354				next_r->stat = MAP_RES_OK;
355			}
356			break;
357		case MAP_REQ_GID:
358			p_group = getgrgid((gid_t) a->id);
359			if (p_group) {
360				next_r->name = my_strdup(p_group->gr_name);
361				next_r->stat = MAP_RES_OK;
362			}
363			break;
364		case MAP_REQ_UNAME:
365			next_r->name = my_strdup(a->name);
366			p_passwd = getpwnam(a->name);
367			if (p_passwd) {
368				next_r->id = p_passwd->pw_uid;
369				next_r->stat = MAP_RES_OK;
370			}
371			break;
372		case MAP_REQ_GNAME:
373			next_r->name = my_strdup(a->name);
374			p_group = getgrnam(a->name);
375			if (p_group) {
376				next_r->id = p_group->gr_gid;
377				next_r->stat = MAP_RES_OK;
378			}
379			break;
380		}
381		if (next_r->name == NULL)
382			next_r->name = my_strdup("");
383		a = a->mapreq_next;
384	}
385
386	res.cm = &no_comment[0];
387
388	return (&res);
389}
390
391
392/*ARGSUSED*/
393v2_alert_results *
394pcnfsd2_alert_2_svc(v2_alert_args *arg, struct svc_req *req)
395{
396	static v2_alert_results res;
397
398	res.stat = ALERT_RES_FAIL;
399	res.cm = &not_supported[0];
400
401	return (&res);
402}
403/*ARGSUSED*/
404v2_info_results *
405pcnfsd2_info_2_svc(v2_info_args *arg, struct svc_req *req)
406{
407	static v2_info_results res;
408	static int facilities[FACILITIESMAX];
409	static int onetime = 1;
410
411#define UNSUPPORTED -1
412#define QUICK 100
413#define SLOW 2000
414
415	if (onetime) {
416		onetime = 0;
417		facilities[PCNFSD2_NULL] = QUICK;
418		facilities[PCNFSD2_INFO] = QUICK;
419		facilities[PCNFSD2_PR_INIT] = QUICK;
420		facilities[PCNFSD2_PR_START] = SLOW;
421		facilities[PCNFSD2_PR_LIST] = QUICK;	/* except first time */
422		facilities[PCNFSD2_PR_QUEUE] = SLOW;
423		facilities[PCNFSD2_PR_STATUS] = SLOW;
424		facilities[PCNFSD2_PR_CANCEL] = SLOW;
425		facilities[PCNFSD2_PR_ADMIN] = UNSUPPORTED;
426		facilities[PCNFSD2_PR_REQUEUE] = UNSUPPORTED;
427		facilities[PCNFSD2_PR_HOLD] = UNSUPPORTED;
428		facilities[PCNFSD2_PR_RELEASE] = UNSUPPORTED;
429		facilities[PCNFSD2_MAPID] = QUICK;
430		facilities[PCNFSD2_AUTH] = QUICK;
431		facilities[PCNFSD2_ALERT] = QUICK;
432	}
433	res.facilities.facilities_len = PCNFSD2_ALERT + 1;
434	res.facilities.facilities_val = facilities;
435
436	res.vers = &pcnfsd_version[0];
437	res.cm = &no_comment[0];
438
439	return (&res);
440}
441
442
443
444void
445fillin_extra_groups(char *uname, gid_t main_gid, int *len, gid_t extra_gids[EXTRAGIDLEN])
446{
447	struct group *grp;
448	__aconst char *__aconst *members;
449	int     n = 0;
450
451	setgrent();
452
453	while (n < EXTRAGIDLEN) {
454		grp = getgrent();
455		if (grp == NULL)
456			break;
457		if (grp->gr_gid == main_gid)
458			continue;
459		for (members = grp->gr_mem; members && *members; members++) {
460			if (!strcmp(*members, uname)) {
461				extra_gids[n++] = grp->gr_gid;
462				break;
463			}
464		}
465	}
466	endgrent();
467	*len = n;
468}
469
470#ifdef USE_YP
471/* the following is from rpcsvc/yp_prot.h */
472#define YPMAXDOMAIN 64
473
474/*
475 * find_entry returns NULL on any error (printing a message) and
476 * otherwise returns a pointer to the malloc'd result. The caller
477 * is responsible for free()ing the result string.
478 */
479char   *
480find_entry(const char *key, const char *map)
481{
482	int     err;
483	char   *val = NULL;
484	char   *cp;
485	int     len = 0;
486	static char domain[YPMAXDOMAIN + 1];
487
488	if (getdomainname(domain, YPMAXDOMAIN)) {
489		msg_out("rpc.pcnfsd: getdomainname failed");
490		return (NULL);
491	}
492	if ((err = yp_bind(domain)) != 0) {
493#ifdef	DEBUG
494		msg_out("rpc.pcnfsd: yp_bind failed");
495#endif
496		return (NULL);
497	}
498	err = yp_match(domain, map, key, strlen(key), &val, &len);
499
500	if (err) {
501		msg_out("rpc.pcnfsd: yp_match failed");
502		if (val)
503			free(val);
504		return (NULL);
505	}
506	if ((cp = strchr(val, '\n')) != NULL)
507		*cp = '\0';	/* in case we get an extra NL at the end */
508	return (val);
509}
510#endif
511