xref: /netbsd/usr.sbin/rpc.pcnfsd/pcnfsd_v2.c (revision d6aaec91)
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 
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   *
pcnfsd2_null_2_svc(void * arg,struct svc_req * req)66 pcnfsd2_null_2_svc(void *arg, struct svc_req *req)
67 {
68 	static char dummy;
69 	return ((void *) &dummy);
70 }
71 
72 v2_auth_results *
pcnfsd2_auth_2_svc(v2_auth_args * arg,struct svc_req * req)73 pcnfsd2_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 
166 v2_pr_init_results *
pcnfsd2_pr_init_2_svc(v2_pr_init_args * arg,struct svc_req * req)167 pcnfsd2_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 
179 v2_pr_start_results *
pcnfsd2_pr_start_2_svc(v2_pr_start_args * arg,struct svc_req * req)180 pcnfsd2_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*/
192 v2_pr_list_results *
pcnfsd2_pr_list_2_svc(void * arg,struct svc_req * req)193 pcnfsd2_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 
205 v2_pr_queue_results *
pcnfsd2_pr_queue_2_svc(v2_pr_queue_args * arg,struct svc_req * req)206 pcnfsd2_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 
220 v2_pr_status_results *
pcnfsd2_pr_status_2_svc(v2_pr_status_args * arg,struct svc_req * req)221 pcnfsd2_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 
234 v2_pr_cancel_results *
pcnfsd2_pr_cancel_2_svc(v2_pr_cancel_args * arg,struct svc_req * req)235 pcnfsd2_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*/
245 v2_pr_requeue_results *
pcnfsd2_pr_requeue_2_svc(v2_pr_requeue_args * arg,struct svc_req * req)246 pcnfsd2_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*/
255 v2_pr_hold_results *
pcnfsd2_pr_hold_2_svc(v2_pr_hold_args * arg,struct svc_req * req)256 pcnfsd2_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*/
266 v2_pr_release_results *
pcnfsd2_pr_release_2_svc(v2_pr_release_args * arg,struct svc_req * req)267 pcnfsd2_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*/
277 v2_pr_admin_results *
pcnfsd2_pr_admin_2_svc(v2_pr_admin_args * arg,struct svc_req * req)278 pcnfsd2_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 
294 void
free_mapreq_results(mapreq_res p)295 free_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 
305 static char *my_strdup(const char *);
306 
307 static char *
my_strdup(const char * s)308 my_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 
318 v2_mapid_results *
pcnfsd2_mapid_2_svc(v2_mapid_args * arg,struct svc_req * req)319 pcnfsd2_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*/
393 v2_alert_results *
pcnfsd2_alert_2_svc(v2_alert_args * arg,struct svc_req * req)394 pcnfsd2_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*/
404 v2_info_results *
pcnfsd2_info_2_svc(v2_info_args * arg,struct svc_req * req)405 pcnfsd2_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 
444 void
fillin_extra_groups(char * uname,gid_t main_gid,int * len,gid_t extra_gids[EXTRAGIDLEN])445 fillin_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  */
479 char   *
find_entry(const char * key,const char * map)480 find_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