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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 = ¬_supported[0]; 251 252 return (&res); 253 } 254 /*ARGSUSED*/ 255 v2_pr_hold_results * 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 = ¬_supported[0]; 262 263 return (&res); 264 } 265 /*ARGSUSED*/ 266 v2_pr_release_results * 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 = ¬_supported[0]; 273 274 return (&res); 275 } 276 /*ARGSUSED*/ 277 v2_pr_admin_results * 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 = ¬_supported[0]; 289 res.stat = PI_RES_FAIL; 290 291 return (&res); 292 } 293 294 void 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 * 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 * 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 * 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 = ¬_supported[0]; 400 401 return (&res); 402 } 403 /*ARGSUSED*/ 404 v2_info_results * 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 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 * 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