34bb1ddc72
as the length in a call to strlcpy(). The previous code would have used the size of a pointer as the length.
549 lines
11 KiB
C
549 lines
11 KiB
C
/* $NetBSD: pcnfsd_v2.c,v 1.13 2014/03/29 18:54:36 apb Exp $ */
|
|
|
|
/* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_v2.c 1.2 91/12/18 13:26:13 SMI */
|
|
/*
|
|
**=====================================================================
|
|
** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
|
|
** @(#)pcnfsd_v2.c 1.2 12/18/91
|
|
**=====================================================================
|
|
*/
|
|
/*
|
|
**=====================================================================
|
|
** I N C L U D E F I L E S E C T I O N *
|
|
** *
|
|
** If your port requires different include files, add a suitable *
|
|
** #define in the customization section, and make the inclusion or *
|
|
** exclusion of the files conditional on this. *
|
|
**=====================================================================
|
|
*/
|
|
|
|
#include <sys/file.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <grp.h>
|
|
#include <netdb.h>
|
|
#include <pwd.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef USE_YP
|
|
#include <rpcsvc/ypclnt.h>
|
|
#endif
|
|
|
|
#ifndef SYSV
|
|
#include <sys/wait.h>
|
|
#endif
|
|
|
|
#ifdef ISC_2_0
|
|
#include <sys/fcntl.h>
|
|
#endif
|
|
|
|
#ifdef SHADOW_SUPPORT
|
|
#include <shadow.h>
|
|
#endif
|
|
|
|
#include "common.h"
|
|
#include "pcnfsd.h"
|
|
#include "extern.h"
|
|
|
|
/*
|
|
**=====================================================================
|
|
** C O D E S E C T I O N *
|
|
**=====================================================================
|
|
*/
|
|
|
|
|
|
static char no_comment[] = "No comment";
|
|
static char not_supported[] = "Not supported";
|
|
static char pcnfsd_version[] = "@(#)pcnfsd_v2.c 1.2 - rpc.pcnfsd V2.0 (c) 1991 Sun Technology Enterprises, Inc.";
|
|
|
|
/*ARGSUSED*/
|
|
void *
|
|
pcnfsd2_null_2_svc(arg, req)
|
|
void *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static char dummy;
|
|
return ((void *) &dummy);
|
|
}
|
|
|
|
v2_auth_results *
|
|
pcnfsd2_auth_2_svc(arg, req)
|
|
v2_auth_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_auth_results r;
|
|
|
|
char uname[32];
|
|
char pw[64];
|
|
int c1, c2;
|
|
struct passwd *p;
|
|
static u_int extra_gids[EXTRAGIDLEN];
|
|
static char home[256];
|
|
#ifdef USE_YP
|
|
char *yphome;
|
|
char *cp;
|
|
#endif /* USE_YP */
|
|
|
|
|
|
r.stat = AUTH_RES_FAIL; /* assume failure */
|
|
r.uid = (int) -2;
|
|
r.gid = (int) -2;
|
|
r.cm = &no_comment[0];
|
|
r.gids.gids_len = 0;
|
|
r.gids.gids_val = &extra_gids[0];
|
|
home[0] = '\0';
|
|
r.home = &home[0];
|
|
r.def_umask = umask(0);
|
|
(void) umask(r.def_umask); /* or use 022 */
|
|
|
|
scramble(arg->id, uname);
|
|
scramble(arg->pw, pw);
|
|
|
|
#ifdef USER_CACHE
|
|
if (check_cache(uname, pw, &r.uid, &r.gid)) {
|
|
r.stat = AUTH_RES_OK;
|
|
#ifdef WTMP
|
|
wlogin(uname, req);
|
|
#endif
|
|
fillin_extra_groups
|
|
(uname, r.gid, &r.gids.gids_len, extra_gids);
|
|
#ifdef USE_YP
|
|
yphome = find_entry(uname, "auto.home");
|
|
if (yphome) {
|
|
strlcpy(home, yphome, sizeof(home));
|
|
free(yphome);
|
|
cp = strchr(home, ':');
|
|
cp++;
|
|
cp = strchr(cp, ':');
|
|
if (cp)
|
|
*cp = '/';
|
|
}
|
|
#endif
|
|
return (&r);
|
|
}
|
|
#endif
|
|
|
|
p = get_password(uname);
|
|
if (p == NULL)
|
|
return (&r);
|
|
|
|
c1 = strlen(pw);
|
|
c2 = strlen(p->pw_passwd);
|
|
if ((c1 && !c2) || (c2 && !c1) ||
|
|
(strcmp(p->pw_passwd, crypt(pw, p->pw_passwd)))) {
|
|
return (&r);
|
|
}
|
|
r.stat = AUTH_RES_OK;
|
|
r.uid = p->pw_uid;
|
|
r.gid = p->pw_gid;
|
|
#ifdef WTMP
|
|
wlogin(uname, req);
|
|
#endif
|
|
fillin_extra_groups(uname, r.gid, &r.gids.gids_len, extra_gids);
|
|
|
|
#ifdef USE_YP
|
|
yphome = find_entry(uname, "auto.home");
|
|
if (yphome) {
|
|
strlcpy(home, yphome, sizeof(home));
|
|
free(yphome);
|
|
cp = strchr(home, ':');
|
|
cp++;
|
|
cp = strchr(cp, ':');
|
|
if (cp)
|
|
*cp = '/';
|
|
}
|
|
#endif
|
|
|
|
#ifdef USER_CACHE
|
|
add_cache_entry(p);
|
|
#endif
|
|
|
|
return (&r);
|
|
|
|
}
|
|
|
|
v2_pr_init_results *
|
|
pcnfsd2_pr_init_2_svc(arg, req)
|
|
v2_pr_init_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_init_results res;
|
|
|
|
res.stat =
|
|
(pirstat) pr_init(arg->system, arg->pn, &res.dir);
|
|
res.cm = &no_comment[0];
|
|
|
|
|
|
return (&res);
|
|
}
|
|
|
|
v2_pr_start_results *
|
|
pcnfsd2_pr_start_2_svc(arg, req)
|
|
v2_pr_start_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_start_results res;
|
|
|
|
res.stat =
|
|
(psrstat) pr_start2(arg->system, arg->pn, arg->user,
|
|
arg->file, arg->opts, &res.id);
|
|
res.cm = &no_comment[0];
|
|
|
|
return (&res);
|
|
}
|
|
/*ARGSUSED*/
|
|
v2_pr_list_results *
|
|
pcnfsd2_pr_list_2_svc(arg, req)
|
|
void *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_list_results res;
|
|
|
|
if (printers == NULL)
|
|
(void) build_pr_list();
|
|
res.cm = &no_comment[0];
|
|
res.printers = printers;
|
|
|
|
return (&res);
|
|
}
|
|
|
|
v2_pr_queue_results *
|
|
pcnfsd2_pr_queue_2_svc(arg, req)
|
|
v2_pr_queue_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_queue_results res;
|
|
|
|
res.stat = build_pr_queue(arg->pn, arg->user,
|
|
arg->just_mine, &res.qlen, &res.qshown);
|
|
res.cm = &no_comment[0];
|
|
res.just_yours = arg->just_mine;
|
|
res.jobs = queue;
|
|
|
|
|
|
return (&res);
|
|
}
|
|
|
|
v2_pr_status_results *
|
|
pcnfsd2_pr_status_2_svc(arg, req)
|
|
v2_pr_status_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_status_results res;
|
|
static char status[128];
|
|
|
|
res.stat = get_pr_status(arg->pn, &res.avail, &res.printing,
|
|
&res.qlen, &res.needs_operator, &status[0], sizeof(status));
|
|
res.status = &status[0];
|
|
res.cm = &no_comment[0];
|
|
|
|
return (&res);
|
|
}
|
|
|
|
v2_pr_cancel_results *
|
|
pcnfsd2_pr_cancel_2_svc(arg, req)
|
|
v2_pr_cancel_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_cancel_results res;
|
|
|
|
res.stat = pr_cancel(arg->pn, arg->user, arg->id);
|
|
res.cm = &no_comment[0];
|
|
|
|
return (&res);
|
|
}
|
|
/*ARGSUSED*/
|
|
v2_pr_requeue_results *
|
|
pcnfsd2_pr_requeue_2_svc(arg, req)
|
|
v2_pr_requeue_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_requeue_results res;
|
|
res.stat = PC_RES_FAIL;
|
|
res.cm = ¬_supported[0];
|
|
|
|
return (&res);
|
|
}
|
|
/*ARGSUSED*/
|
|
v2_pr_hold_results *
|
|
pcnfsd2_pr_hold_2_svc(arg, req)
|
|
v2_pr_hold_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_hold_results res;
|
|
|
|
res.stat = PC_RES_FAIL;
|
|
res.cm = ¬_supported[0];
|
|
|
|
return (&res);
|
|
}
|
|
/*ARGSUSED*/
|
|
v2_pr_release_results *
|
|
pcnfsd2_pr_release_2_svc(arg, req)
|
|
v2_pr_release_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_release_results res;
|
|
|
|
res.stat = PC_RES_FAIL;
|
|
res.cm = ¬_supported[0];
|
|
|
|
return (&res);
|
|
}
|
|
/*ARGSUSED*/
|
|
v2_pr_admin_results *
|
|
pcnfsd2_pr_admin_2_svc(arg, req)
|
|
v2_pr_admin_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_pr_admin_results res;
|
|
/*
|
|
** The default action for admin is to fail.
|
|
** If someone wishes to implement an administration
|
|
** mechanism, and isn't worried about the security
|
|
** holes, go right ahead.
|
|
*/
|
|
|
|
res.cm = ¬_supported[0];
|
|
res.stat = PI_RES_FAIL;
|
|
|
|
return (&res);
|
|
}
|
|
|
|
void
|
|
free_mapreq_results(p)
|
|
mapreq_res p;
|
|
{
|
|
if (p->mapreq_next)
|
|
free_mapreq_results(p->mapreq_next); /* recurse */
|
|
if (p->name)
|
|
(void) free(p->name);
|
|
(void) free(p);
|
|
return;
|
|
}
|
|
|
|
static char *my_strdup __P((const char *));
|
|
|
|
static char *
|
|
my_strdup(s)
|
|
const char *s;
|
|
{
|
|
size_t len;
|
|
char *r;
|
|
len = strlen(s);
|
|
r = (char *) grab(len + 1);
|
|
memcpy(r, s, len + 1);
|
|
return (r);
|
|
}
|
|
|
|
v2_mapid_results *
|
|
pcnfsd2_mapid_2_svc(arg, req)
|
|
v2_mapid_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_mapid_results res;
|
|
struct passwd *p_passwd;
|
|
struct group *p_group;
|
|
|
|
mapreq_arg a;
|
|
mapreq_res next_r;
|
|
mapreq_res last_r = NULL;
|
|
|
|
|
|
if (res.res_list) {
|
|
free_mapreq_results(res.res_list);
|
|
res.res_list = NULL;
|
|
}
|
|
a = arg->req_list;
|
|
while (a) {
|
|
next_r = (struct mapreq_res_item *)
|
|
grab(sizeof(struct mapreq_res_item));
|
|
next_r->stat = MAP_RES_UNKNOWN;
|
|
next_r->req = a->req;
|
|
next_r->id = a->id;
|
|
next_r->name = NULL;
|
|
next_r->mapreq_next = NULL;
|
|
|
|
if (last_r == NULL)
|
|
res.res_list = next_r;
|
|
else
|
|
last_r->mapreq_next = next_r;
|
|
last_r = next_r;
|
|
switch (a->req) {
|
|
case MAP_REQ_UID:
|
|
p_passwd = getpwuid((uid_t) a->id);
|
|
if (p_passwd) {
|
|
next_r->name = my_strdup(p_passwd->pw_name);
|
|
next_r->stat = MAP_RES_OK;
|
|
}
|
|
break;
|
|
case MAP_REQ_GID:
|
|
p_group = getgrgid((gid_t) a->id);
|
|
if (p_group) {
|
|
next_r->name = my_strdup(p_group->gr_name);
|
|
next_r->stat = MAP_RES_OK;
|
|
}
|
|
break;
|
|
case MAP_REQ_UNAME:
|
|
next_r->name = my_strdup(a->name);
|
|
p_passwd = getpwnam(a->name);
|
|
if (p_passwd) {
|
|
next_r->id = p_passwd->pw_uid;
|
|
next_r->stat = MAP_RES_OK;
|
|
}
|
|
break;
|
|
case MAP_REQ_GNAME:
|
|
next_r->name = my_strdup(a->name);
|
|
p_group = getgrnam(a->name);
|
|
if (p_group) {
|
|
next_r->id = p_group->gr_gid;
|
|
next_r->stat = MAP_RES_OK;
|
|
}
|
|
break;
|
|
}
|
|
if (next_r->name == NULL)
|
|
next_r->name = my_strdup("");
|
|
a = a->mapreq_next;
|
|
}
|
|
|
|
res.cm = &no_comment[0];
|
|
|
|
return (&res);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
v2_alert_results *
|
|
pcnfsd2_alert_2_svc(arg, req)
|
|
v2_alert_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_alert_results res;
|
|
|
|
res.stat = ALERT_RES_FAIL;
|
|
res.cm = ¬_supported[0];
|
|
|
|
return (&res);
|
|
}
|
|
/*ARGSUSED*/
|
|
v2_info_results *
|
|
pcnfsd2_info_2_svc(arg, req)
|
|
v2_info_args *arg;
|
|
struct svc_req *req;
|
|
{
|
|
static v2_info_results res;
|
|
static int facilities[FACILITIESMAX];
|
|
static int onetime = 1;
|
|
|
|
#define UNSUPPORTED -1
|
|
#define QUICK 100
|
|
#define SLOW 2000
|
|
|
|
if (onetime) {
|
|
onetime = 0;
|
|
facilities[PCNFSD2_NULL] = QUICK;
|
|
facilities[PCNFSD2_INFO] = QUICK;
|
|
facilities[PCNFSD2_PR_INIT] = QUICK;
|
|
facilities[PCNFSD2_PR_START] = SLOW;
|
|
facilities[PCNFSD2_PR_LIST] = QUICK; /* except first time */
|
|
facilities[PCNFSD2_PR_QUEUE] = SLOW;
|
|
facilities[PCNFSD2_PR_STATUS] = SLOW;
|
|
facilities[PCNFSD2_PR_CANCEL] = SLOW;
|
|
facilities[PCNFSD2_PR_ADMIN] = UNSUPPORTED;
|
|
facilities[PCNFSD2_PR_REQUEUE] = UNSUPPORTED;
|
|
facilities[PCNFSD2_PR_HOLD] = UNSUPPORTED;
|
|
facilities[PCNFSD2_PR_RELEASE] = UNSUPPORTED;
|
|
facilities[PCNFSD2_MAPID] = QUICK;
|
|
facilities[PCNFSD2_AUTH] = QUICK;
|
|
facilities[PCNFSD2_ALERT] = QUICK;
|
|
}
|
|
res.facilities.facilities_len = PCNFSD2_ALERT + 1;
|
|
res.facilities.facilities_val = facilities;
|
|
|
|
res.vers = &pcnfsd_version[0];
|
|
res.cm = &no_comment[0];
|
|
|
|
return (&res);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
fillin_extra_groups(uname, main_gid, len, extra_gids)
|
|
char *uname;
|
|
gid_t main_gid;
|
|
int *len;
|
|
gid_t extra_gids[EXTRAGIDLEN];
|
|
{
|
|
struct group *grp;
|
|
__aconst char *__aconst *members;
|
|
int n = 0;
|
|
|
|
setgrent();
|
|
|
|
while (n < EXTRAGIDLEN) {
|
|
grp = getgrent();
|
|
if (grp == NULL)
|
|
break;
|
|
if (grp->gr_gid == main_gid)
|
|
continue;
|
|
for (members = grp->gr_mem; members && *members; members++) {
|
|
if (!strcmp(*members, uname)) {
|
|
extra_gids[n++] = grp->gr_gid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
endgrent();
|
|
*len = n;
|
|
}
|
|
|
|
#ifdef USE_YP
|
|
/* the following is from rpcsvc/yp_prot.h */
|
|
#define YPMAXDOMAIN 64
|
|
|
|
/*
|
|
* find_entry returns NULL on any error (printing a message) and
|
|
* otherwise returns a pointer to the malloc'd result. The caller
|
|
* is responsible for free()ing the result string.
|
|
*/
|
|
char *
|
|
find_entry(key, map)
|
|
const char *key;
|
|
const char *map;
|
|
{
|
|
int err;
|
|
char *val = NULL;
|
|
char *cp;
|
|
int len = 0;
|
|
static char domain[YPMAXDOMAIN + 1];
|
|
|
|
if (getdomainname(domain, YPMAXDOMAIN)) {
|
|
msg_out("rpc.pcnfsd: getdomainname failed");
|
|
return (NULL);
|
|
}
|
|
if ((err = yp_bind(domain)) != 0) {
|
|
#ifdef DEBUG
|
|
msg_out("rpc.pcnfsd: yp_bind failed");
|
|
#endif
|
|
return (NULL);
|
|
}
|
|
err = yp_match(domain, map, key, strlen(key), &val, &len);
|
|
|
|
if (err) {
|
|
msg_out("rpc.pcnfsd: yp_match failed");
|
|
if (val)
|
|
free(val);
|
|
return (NULL);
|
|
}
|
|
if ((cp = strchr(val, '\n')) != NULL)
|
|
*cp = '\0'; /* in case we get an extra NL at the end */
|
|
return (val);
|
|
}
|
|
#endif
|