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 = ¬_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 = ¬_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 = ¬_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 = ¬_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 = ¬_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