pcnfsd_misc.c revision 1.3 1 /* $NetBSD: pcnfsd_misc.c,v 1.3 1997/10/25 13:45:57 lukem Exp $ */
2
3 /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_misc.c 1.5 92/01/24 19:59:13 SMI */
4 /*
5 **=====================================================================
6 ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
7 ** @(#)pcnfsd_misc.c 1.5 1/24/92
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/socket.h>
23 #include <sys/stat.h>
24 #include <sys/time.h>
25 #include <sys/wait.h>
26
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29
30 #include <ctype.h>
31 #include <errno.h>
32 #include <netdb.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 #ifdef ISC_2_0
41 #include <sys/fcntl.h>
42 #endif
43
44 #ifdef SHADOW_SUPPORT
45 #include <shadow.h>
46 #endif
47
48 #ifdef WTMP
49 int wtmp_enabled = 1;
50 #endif
51
52 #include "common.h"
53 #include "pcnfsd.h"
54 #include "extern.h"
55
56 /*
57 **---------------------------------------------------------------------
58 ** Other #define's
59 **---------------------------------------------------------------------
60 */
61
62 #define zchar 0x5b
63
64 char tempstr[256];
65
66 char *mapfont __P((char, char, char));
67 void myhandler __P((int));
68 void start_watchdog __P((int));
69 void stop_watchdog __P((void));
70
71 /*
72 **=====================================================================
73 ** C O D E S E C T I O N *
74 **=====================================================================
75 */
76 /*
77 **---------------------------------------------------------------------
78 ** Support procedures
79 **---------------------------------------------------------------------
80 */
81
82
83 void
84 scramble(s1, s2)
85 char *s1;
86 char *s2;
87 {
88 while (*s1) {
89 *s2++ = (*s1 ^ zchar) & 0x7f;
90 s1++;
91 }
92 *s2 = 0;
93 }
94
95
96
97 struct passwd *
98 get_password(usrnam)
99 char *usrnam;
100 {
101 struct passwd *p;
102 static struct passwd localp;
103 char *pswd;
104 char *ushell;
105
106
107 #ifdef SHADOW_SUPPORT
108 struct spwd *sp;
109 int shadowfile;
110 #endif
111
112 #ifdef SHADOW_SUPPORT
113 /*
114 **--------------------------------------------------------------
115 ** Check the existence of SHADOW. If it is there, then we are
116 ** running a two-password-file system.
117 **--------------------------------------------------------------
118 */
119 if (access(SHADOW, 0))
120 shadowfile = 0; /* SHADOW is not there */
121 else
122 shadowfile = 1;
123
124 setpwent();
125 if (shadowfile)
126 (void) setspent(); /* Setting the shadow password file */
127 if ((p = getpwnam(usrnam)) == (struct passwd *) NULL ||
128 (shadowfile && (sp = getspnam(usrnam)) == (struct spwd *) NULL))
129 return ((struct passwd *) NULL);
130
131 if (shadowfile) {
132 pswd = sp->sp_pwdp;
133 (void) endspent();
134 } else
135 pswd = p->pw_passwd;
136
137 #else
138 p = getpwnam(usrnam);
139 if (p == (struct passwd *) NULL)
140 return ((struct passwd *) NULL);
141 pswd = p->pw_passwd;
142 #endif
143
144 #ifdef ISC_2_0
145 /* *----------------------------------------------------------- * We
146 * may have an 'x' in which case look in /etc/shadow ..
147 * *----------------------------------------------------------- */
148 if (((strlen(pswd)) == 1) && pswd[0] == 'x') {
149 struct spwd *shadow = getspnam(usrnam);
150
151 if (!shadow)
152 return ((struct passwd *) NULL);
153 pswd = shadow->sp_pwdp;
154 }
155 #endif
156 localp = *p;
157 localp.pw_passwd = pswd;
158 #ifdef USE_GETUSERSHELL
159
160 setusershell();
161 while (ushell = getusershell()) {
162 if (!strcmp(ushell, localp.pw_shell)) {
163 ok = 1;
164 break;
165 }
166 }
167 endusershell();
168 if (!ok)
169 return ((struct passwd *) NULL);
170 #else
171 /*
172 * the best we can do is to ensure that the shell ends in "sh"
173 */
174 ushell = localp.pw_shell;
175 if (strlen(ushell) < 2)
176 return ((struct passwd *) NULL);
177 ushell += strlen(ushell) - 2;
178 if (strcmp(ushell, "sh"))
179 return ((struct passwd *) NULL);
180
181 #endif
182 return (&localp);
183 }
184
185
186
187 /*
188 **---------------------------------------------------------------------
189 ** Print support procedures
190 **---------------------------------------------------------------------
191 */
192
193
194 char *
195 mapfont(f, i, b)
196 char f;
197 char i;
198 char b;
199 {
200 static char fontname[64];
201
202 fontname[0] = 0; /* clear it out */
203
204 switch (f) {
205 case 'c':
206 (void) strcpy(fontname, "Courier");
207 break;
208 case 'h':
209 (void) strcpy(fontname, "Helvetica");
210 break;
211 case 't':
212 (void) strcpy(fontname, "Times");
213 break;
214 default:
215 (void) strcpy(fontname, "Times-Roman");
216 goto finis;
217 }
218 if (i != 'o' && b != 'b') { /* no bold or oblique */
219 if (f == 't') /* special case Times */
220 (void) strcat(fontname, "-Roman");
221 goto finis;
222 }
223 (void) strcat(fontname, "-");
224 if (b == 'b')
225 (void) strcat(fontname, "Bold");
226 if (i == 'o') /* o-blique */
227 (void) strcat(fontname, f == 't' ? "Italic" : "Oblique");
228
229 finis: return (&fontname[0]);
230 }
231 /*
232 * run_ps630 performs the Diablo 630 emulation filtering process. ps630
233 * was broken in certain Sun releases: it would not accept point size or
234 * font changes. If your version is fixed, undefine the symbol
235 * PS630_IS_BROKEN and rebuild pc-nfsd.
236 */
237 /* #define PS630_IS_BROKEN 1 */
238
239 void
240 run_ps630(f, opts)
241 char *f;
242 char *opts;
243 {
244 char temp_file[256];
245 char commbuf[256];
246 int i;
247
248 (void) strcpy(temp_file, f);
249 (void) strcat(temp_file, "X"); /* intermediate file name */
250
251 #ifndef PS630_IS_BROKEN
252 (void) sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
253 opts[2], opts[3], temp_file);
254 (void) strcat(commbuf, mapfont(opts[4], opts[5], opts[6]));
255 (void) strcat(commbuf, " -F ");
256 (void) strcat(commbuf, mapfont(opts[7], opts[8], opts[9]));
257 (void) strcat(commbuf, " ");
258 (void) strcat(commbuf, f);
259 #else /* PS630_IS_BROKEN */
260 /*
261 * The pitch and font features of ps630 appear to be broken at
262 * this time.
263 */
264 (void) sprintf(commbuf, "ps630 -p %s %s", temp_file, f);
265 #endif /* PS630_IS_BROKEN */
266
267
268 if ((i = system(commbuf)) != 0) {
269 /*
270 * Under (un)certain conditions, ps630 may return -1 even
271 * if it worked. Hence the commenting out of this error
272 * report.
273 */
274 /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
275 /* exit(1); */
276 }
277 if (rename(temp_file, f)) {
278 perror("run_ps630: rename");
279 exit(1);
280 }
281 return;
282 }
283
284
285
286
287
288 /*
289 **---------------------------------------------------------------------
290 ** WTMP update support
291 **---------------------------------------------------------------------
292 */
293
294
295 #ifdef WTMP
296
297 #include <utmp.h>
298
299 #ifndef _PATH_WTMP
300 #define _PATH_WTMP "/usr/adm/wtmp"
301 #endif
302
303 void
304 wlogin(name, req)
305 char *name;
306 struct svc_req *req;
307 {
308 struct sockaddr_in *who;
309 struct hostent *hp;
310 char *host;
311 struct utmp ut;
312 int fd;
313
314 if (!wtmp_enabled)
315 return;
316
317 /* Get network address of client. */
318 who = &req->rq_xprt->xp_raddr;
319
320 /* Get name of connected client */
321 hp = gethostbyaddr((char *) &who->sin_addr,
322 sizeof(struct in_addr),
323 who->sin_family);
324
325 if (hp && (strlen(hp->h_name) <= sizeof(ut.ut_host))) {
326 host = hp->h_name;
327 } else {
328 host = inet_ntoa(who->sin_addr);
329 }
330
331 (void) strcpy(ut.ut_line, "PC-NFS");
332 (void) strncpy(ut.ut_name, name, sizeof ut.ut_name);
333 (void) strncpy(ut.ut_host, host, sizeof ut.ut_host);
334 ut.ut_time = time((time_t *) 0);
335
336 if ((fd = open(_PATH_WTMP, O_WRONLY | O_APPEND, 0)) >= 0) {
337 (void) write(fd, (char *) &ut, sizeof(struct utmp));
338 (void) close(fd);
339 }
340 }
341 #endif /* WTMP */
342
343
344 /*
345 **---------------------------------------------------------------------
346 ** Run-process-as-user procedures
347 **---------------------------------------------------------------------
348 */
349
350
351 #define READER_FD 0
352 #define WRITER_FD 1
353
354 static int child_pid;
355
356 static char cached_user[64] = "";
357 static uid_t cached_uid;
358 static gid_t cached_gid;
359
360 static struct sigaction old_action;
361 static struct sigaction new_action;
362 static struct itimerval timer;
363
364 int interrupted = 0;
365 static FILE *pipe_handle;
366
367 void
368 myhandler(dummy)
369 int dummy;
370 {
371 interrupted = 1;
372 fclose(pipe_handle);
373 kill(child_pid, SIGKILL);
374 msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
375 }
376
377 void
378 start_watchdog(n)
379 int n;
380 {
381 /*
382 * Setup SIGALRM handler, force interrupt of ongoing syscall
383 */
384
385 new_action.sa_handler = myhandler;
386 sigemptyset(&(new_action.sa_mask));
387 new_action.sa_flags = 0;
388 #ifdef SA_INTERRUPT
389 new_action.sa_flags |= SA_INTERRUPT;
390 #endif
391 sigaction(SIGALRM, &new_action, &old_action);
392
393 /*
394 * Set interval timer for n seconds
395 */
396 timer.it_interval.tv_sec = 0;
397 timer.it_interval.tv_usec = 0;
398 timer.it_value.tv_sec = n;
399 timer.it_value.tv_usec = 0;
400 setitimer(ITIMER_REAL, &timer, NULL);
401 interrupted = 0;
402
403 }
404
405 void
406 stop_watchdog()
407 {
408 /*
409 * Cancel timer
410 */
411
412 timer.it_interval.tv_sec = 0;
413 timer.it_interval.tv_usec = 0;
414 timer.it_value.tv_sec = 0;
415 timer.it_value.tv_usec = 0;
416 setitimer(ITIMER_REAL, &timer, NULL);
417
418 /*
419 * restore old signal handling
420 */
421 sigaction(SIGALRM, &old_action, NULL);
422 }
423
424 FILE *
425 su_popen(user, cmd, maxtime)
426 char *user;
427 char *cmd;
428 int maxtime;
429 {
430 int p[2];
431 int parent_fd, child_fd, pid;
432 struct passwd *pw;
433
434 if (strcmp(cached_user, user)) {
435 pw = getpwnam(user);
436 if (!pw)
437 pw = getpwnam("nobody");
438 if (pw) {
439 cached_uid = pw->pw_uid;
440 cached_gid = pw->pw_gid;
441 strcpy(cached_user, user);
442 } else {
443 cached_uid = (uid_t) (-2);
444 cached_gid = (gid_t) (-2);
445 cached_user[0] = '\0';
446 }
447 }
448 if (pipe(p) < 0) {
449 msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
450 return (NULL);
451 }
452 parent_fd = p[READER_FD];
453 child_fd = p[WRITER_FD];
454 if ((pid = fork()) == 0) {
455 int i;
456
457 for (i = 0; i < 10; i++)
458 if (i != child_fd)
459 (void) close(i);
460 if (child_fd != 1) {
461 (void) dup2(child_fd, 1);
462 (void) close(child_fd);
463 }
464 dup2(1, 2); /* let's get stderr as well */
465
466 (void) setgid(cached_gid);
467 (void) setuid(cached_uid);
468
469 (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
470 _exit(255);
471 }
472 if (pid == -1) {
473 msg_out("rpc.pcnfsd: fork failed");
474 close(parent_fd);
475 close(child_fd);
476 return (NULL);
477 }
478 child_pid = pid;
479 close(child_fd);
480 start_watchdog(maxtime);
481 pipe_handle = fdopen(parent_fd, "r");
482 return (pipe_handle);
483 }
484
485 int
486 su_pclose(ptr)
487 FILE *ptr;
488 {
489 int pid, status;
490
491 stop_watchdog();
492
493 fclose(ptr);
494 if (child_pid == -1)
495 return (-1);
496 while ((pid = wait(&status)) != child_pid && pid != -1);
497 return (pid == -1 ? -1 : status);
498 }
499
500
501
502 #if XXX_unused
503 /*
504 ** The following routine reads a file "/etc/pcnfsd.conf" if present,
505 ** and uses it to replace certain builtin elements, like the
506 ** name of the print spool directory. The configuration file
507 ** Is the usual kind: Comments begin with '#', blank lines are ignored,
508 ** and valid lines are of the form
509 **
510 ** <keyword><whitespace><value>
511 **
512 ** The following keywords are recognized:
513 **
514 ** spooldir
515 ** printer name alias-for command
516 ** wtmp yes|no
517 */
518 void
519 config_from_file()
520 {
521 FILE *fd;
522 char buff[1024];
523 char *cp;
524 char *kw;
525 char *val;
526 char *arg1;
527 char *arg2;
528
529 if ((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL)
530 return;
531 while (fgets(buff, 1024, fd)) {
532 cp = strchr(buff, '\n');
533 *cp = '\0';
534 cp = strchr(buff, '#');
535 if (cp)
536 *cp = '\0';
537 kw = strtok(buff, " \t");
538 if (kw == NULL)
539 continue;
540 val = strtok(NULL, " \t");
541 if (val == NULL)
542 continue;
543 if (!strcasecmp(kw, "spooldir")) {
544 strcpy(sp_name, val);
545 continue;
546 }
547 #ifdef WTMP
548 if (!strcasecmp(kw, "wtmp")) {
549 /* assume default is YES, just look for negatives */
550 if (!strcasecmp(val, "no") ||
551 !strcasecmp(val, "off") ||
552 !strcasecmp(val, "disable") ||
553 !strcmp(val, "0"))
554 wtmp_enabled = 0;;
555 continue;
556 }
557 #endif
558 if (!strcasecmp(kw, "printer")) {
559 arg1 = strtok(NULL, " \t");
560 arg2 = strtok(NULL, "");
561 (void) add_printer_alias(val, arg1, arg2);
562 continue;
563 }
564 /*
565 ** Add new cases here
566 */
567 }
568 fclose(fd);
569 }
570 #endif /* XXX_unused */
571
572
573 /*
574 ** strembedded - returns true if s1 is embedded (in any case) in s2
575 */
576
577 int
578 strembedded(s1, s2)
579 const char *s1;
580 const char *s2;
581 {
582 while (*s2) {
583 if (!strcasecmp(s1, s2))
584 return 1;
585 s2++;
586 }
587 return 0;
588 }
589