PageRenderTime 217ms CodeModel.GetById 157ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 1ms

/src/qsnet/mqshd.c

https://code.google.com/
C | 523 lines | 305 code | 88 blank | 130 comment | 72 complexity | 887e2c21394dff279c876e5a3321395d MD5 | raw file
  1/*****************************************************************************\
  2 *  $Id$
  3 *****************************************************************************
  4 *  Copyright (C) 2001-2006 The Regents of the University of California.
  5 *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  6 *  Written by Jim Garlick <garlick@llnl.gov>.
  7 *  UCRL-CODE-2003-005.
  8 *  
  9 *  This file is part of Pdsh, a parallel remote shell program.
 10 *  For details, see <http://www.llnl.gov/linux/pdsh/>.
 11 *  
 12 *  Pdsh is free software; you can redistribute it and/or modify it under
 13 *  the terms of the GNU General Public License as published by the Free
 14 *  Software Foundation; either version 2 of the License, or (at your option)
 15 *  any later version.
 16 *  
 17 *  Pdsh is distributed in the hope that it will be useful, but WITHOUT ANY
 18 *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 19 *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 20 *  details.
 21 *  
 22 *  You should have received a copy of the GNU General Public License along
 23 *  with Pdsh; if not, write to the Free Software Foundation, Inc.,
 24 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 25\*****************************************************************************/
 26
 27/*-
 28 * Started with BSD rshd which is:
 29 *
 30 * Copyright (c) 1988, 1989 The Regents of the University of California.
 31 * All rights reserved.
 32 *
 33 * Redistribution and use in source and binary forms, with or without
 34 * modification, are permitted provided that the following conditions
 35 * are met:
 36 * 1. Redistributions of source code must retain the above copyright
 37 *    notice, this list of conditions and the following disclaimer.
 38 *
 39 * 2. Redistributions in binary form must reproduce the above copyright
 40 *    notice, this list of conditions and the following disclaimer in the
 41 *    documentation and/or other materials provided with the distribution.
 42 *
 43 * 3. All advertising materials mentioning features or use of this software
 44 *    must display the following acknowledgement:
 45 *      This product includes software developed by the University of
 46 *      California, Berkeley and its contributors.
 47 *
 48 * 4. Neither the name of the University nor the names of its contributors
 49 *    may be used to endorse or promote products derived from this software
 50 *    without specific prior written permission.
 51 *
 52 * 5. This is free software; you can redistribute it and/or modify it
 53 *    under the terms of the GNU General Public License as published
 54 *    by the Free Software Foundation; either version 2 of the
 55 *    License, or (at your option) any later version.
 56 *                              
 57 * 6. This is distributed in the hope that it will be useful, but
 58 *    WITHOUT ANY WARRANTY; without even the implied warranty of
 59 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 60 *    GNU General Public License for more details.
 61 *                                                           
 62 * 7. You should have received a copy of the GNU General Public License;
 63 *    if not, write to the Free Software Foundation, Inc., 59 Temple
 64 *    Place, Suite 330, Boston, MA  02111-1307  USA.
 65 *
 66 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 67 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 68 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 69 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 70 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 71 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 72 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 73 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 74 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 75 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 76 * SUCH DAMAGE.
 77 */
 78
 79/*
 80 * PAM modifications by Michael K. Johnson <johnsonm@redhat.com>
 81 */
 82
 83char copyright[] =
 84"@(#) Copyright (c) 1988, 1989, 2003 The Regents of the University of California.\n"
 85"All rights reserved.\n";
 86
 87/*
 88 * From: @(#)mqshd.c     5.38 (Berkeley) 3/2/91
 89 */
 90char rcsid[] = "$Id$";
 91/* #include "version.h" */
 92
 93#if     HAVE_CONFIG_H
 94#include "config.h"
 95#endif
 96
 97#if HAVE_UNISTD_H     
 98#include <unistd.h>
 99#endif
100
101#include <fcntl.h>
102#include <sys/socket.h>           /* connect */
103#include <sys/types.h>
104#include <netinet/in.h>           /* sockaddr_in, htons */
105#include <arpa/inet.h>            /* inet_ntoa */
106#include <netdb.h>                /* gethostbyname */ 
107#include <net/if.h>               /* struct ifconf, struct ifreq */
108#include <sys/ioctl.h>            /* ioctl */
109#include <sys/param.h>            /* MAXHOSTNAMELEN / INET_ADDRSTRLEN */
110
111#include <stdio.h>  
112#include <stdlib.h>
113#include <string.h>
114#include <syslog.h>
115#include <errno.h>
116#include <munge.h>
117
118#include "src/common/fd.h"
119#include "src/common/xmalloc.h"
120#include "qshell.h"
121
122#ifndef MAXHOSTNAMELEN
123#define MAXHOSTNAMELEN 64
124#endif
125
126#ifndef INET_ADDRSTRLEN
127#define INET_ADDRSTRLEN 16
128#endif
129
130#define MAX_MBUF_SIZE 4096
131
132extern int paranoid;
133extern int sent_null;
134
135#define ERRMSGLEN           4096
136static char errmsgbuf[ERRMSGLEN];
137static const char *errmsg = NULL;
138
139#if USE_PAM
140extern char *pam_errmsg;
141#endif
142
143static char *munge_parse(char *buf, char *buf_end) {
144    int len = strlen(buf);
145
146    buf += (len + 1);
147    if (buf >= buf_end) {
148        syslog(LOG_ERR, "parser went beyond valid data");
149        errmsg = "Internal Error";
150        return NULL;
151    }
152    return buf;
153}
154
155static int getifrlen(struct ifreq *ifr) {
156    int len;
157
158    /* Calculations below are necessary b/c socket addresses can have
159     * variable length 
160     */
161
162#if HAVE_SA_LEN
163    if (sizeof(struct sockaddr) > ifr->ifr_addr.sa_len)
164        len = sizeof(struct sockaddr);
165    else
166        len = ifr->ifr_addr.sa_len;
167#else /* !HAVE_SA_LEN */
168    /* For now we only assume AF_INET and AF_INET6 */
169    switch(ifr->ifr_addr.sa_family) {
170#ifdef HAVE_IPV6
171        case AF_INET6:
172            len = sizeof(struct sockaddr_in6);
173            break;
174#endif /* HAVE_IPV6 */
175        case AF_INET:
176        default:
177            len = sizeof(struct sockaddr_in);
178            break;
179    }
180
181    /* On ia32 struct sockaddr_in6/sockaddr_in was the largest
182     * structure in struct ifreq, but not on ia64.  This fixes things
183     */
184    if (len < (sizeof(struct ifreq) - IFNAMSIZ))
185        len = sizeof(struct ifreq) - IFNAMSIZ;
186
187#endif /* HAVE_SA_LEN */ 
188
189    return len;
190}
191
192static int check_interfaces(void *munge_addr, int addr_len) {
193    struct ifconf ifc;
194    struct ifreq *ifr;
195    int s, found = 0, lastlen = -1;
196    int len = sizeof(struct ifreq) * 100;
197    void *buf = NULL, *ptr = NULL;
198    struct sockaddr_in *sin;
199    char *addr;
200
201    /* Significant amounts of this code are from Unix Network
202     * Programming, by R. Stevens, Chapter 16
203     */
204
205    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
206        syslog(LOG_ERR, "socket call failed: %m");
207        errmsg = "Internal System Error";
208        goto bad;
209    }
210
211    /* get all active interfaces */
212    while(1) {
213        if ((buf = (char *)malloc(len)) == NULL) {
214            syslog(LOG_ERR, "malloc failed: %m");
215            errmsg = "Out of Memory";
216            goto bad;
217        }
218
219        ifc.ifc_len = len;
220        ifc.ifc_buf = buf;
221
222        if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
223            syslog(LOG_ERR, "ioctl SIOCGIFCONF failed: %m");
224            errmsg = "Internal System Error";
225            goto bad;
226        }
227        else {
228            if (ifc.ifc_len == lastlen)
229                break;
230
231            lastlen = ifc.ifc_len;
232        }
233
234        /* Run ioctl() twice for portability reasons.  See Unix Network
235         * Programming, section 16.6
236         */
237
238        len += 10 * sizeof(struct ifreq);
239        free(buf);
240    }
241
242    /* get IP addresses for all interfaces */
243    for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
244
245        ifr = (struct ifreq *)ptr;
246
247        len = getifrlen(ifr);
248
249        ptr += sizeof(ifr->ifr_name) + len;
250
251        /* Currently, we only care about IPv4 (i.e. AF_INET) */
252        if (ifr->ifr_addr.sa_family != AF_INET)
253            continue;
254
255        sin = (struct sockaddr_in *)&ifr->ifr_addr;
256
257        /* Skip 127.0.0.1 */
258        addr = inet_ntoa(sin->sin_addr);
259        if (strcmp(addr,"127.0.0.1") == 0)
260            continue;
261
262        if (memcmp(munge_addr, (void *)&sin->sin_addr.s_addr, addr_len) == 0) {
263            found++;
264            break;
265        }
266    }
267
268    free(buf);
269    return found;
270
271bad:
272    free(buf);
273    return -1;
274}
275
276static int check_munge_ip(char *ip) {
277    struct in_addr in;
278    char ipbuf[INET_ADDRSTRLEN];
279
280    strncpy(ipbuf, ip, INET_ADDRSTRLEN);
281    ipbuf[INET_ADDRSTRLEN-1] = '\0';
282
283    if (inet_pton(AF_INET, ipbuf, &in) <= 0) {
284        syslog(LOG_ERR, "failed inet_pton: %m");
285        errmsg = "Internal System Error";
286        return -1;
287    }
288    
289    return check_interfaces(&in, sizeof(struct in_addr));
290}
291
292
293static void mqshell_get_args(struct sockaddr_in *fromp, 
294                             struct qshell_args *args) 
295{
296    struct sockaddr_in sin;
297    struct passwd cred;
298    int rv = -1;
299    int buf_length;
300    unsigned short port = 0;
301    unsigned int randnum;
302    char *mptr = NULL;
303    char *m_end = NULL;
304    char *m_head = NULL;
305    char mbuf[MAX_MBUF_SIZE];
306    char cmdbuf[ARG_MAX + 1];
307
308    errmsg = NULL;
309
310    args->sock = -1;
311
312    /* read munge blob for authentication */
313    memset(&mbuf[0],0,sizeof(mbuf));
314    if ((buf_length = fd_null_read_n(0, &mbuf[0], MAX_MBUF_SIZE)) < 0) {
315        syslog(LOG_ERR, "%s: %m", "mqshd: bad read error.");
316        errmsg = "Internal System Error";
317        goto error_out;
318    }
319
320    if (buf_length == 0) {
321        syslog(LOG_ERR, "mqshd: null munge credential.");
322        errmsg = "Protocol Error";
323        goto error_out;
324    }
325
326    /*
327     * The format of our munge buffer is as follows (each a string terminated
328     * with a '\0' (null):
329     *
330     *                                            SIZE            EXAMPLE
331     *                                            ==========      =============
332     * remote_user_name                           variable        "mhaskell"
333     * '\0'
334     * dotted_decimal_address_of_this_server      7-15 bytes      "134.9.11.155"
335     * '\0'
336     * stderr_port_number                         4-8 bytes       "50111"
337     * '\0
338     * random number                              1-8 bytes       "1f79ca0e"
339     * '\0'
340     * users_command                              variable        "ls -al"
341     * '\0' '\0'
342     *
343     */
344    mptr = &mbuf[0];
345    if ((rv = munge_decode(mbuf,0,(void **)&mptr,&buf_length,
346                    &cred.pw_uid,&cred.pw_gid)) != EMUNGE_SUCCESS) {
347
348        syslog(LOG_ERR, "%s: %s", "munge_decode error", munge_strerror(rv));
349        snprintf(errmsgbuf, ERRMSGLEN, "Authentication Failure: %s",
350                 munge_strerror(rv));
351        errmsg = &errmsgbuf[0];
352        goto error_out;
353    }
354
355    if ((mptr == NULL) || (buf_length <= 0)) {
356        syslog(LOG_ERR, "Null munge buffer");
357        errmsg = "Protocol Error";
358        goto error_out;
359    }
360
361    m_head = mptr;
362    m_end = mptr + buf_length;
363
364    /* Verify User Id */
365
366    if ((args->pwd = getpwnam_common(m_head)) == NULL) {
367        syslog(LOG_ERR, "bad getpwnam(): %m");
368        errmsg = "Permission Denied";
369        goto error_out;
370    }
371
372    if ((args->pwd->pw_uid != cred.pw_uid) && cred.pw_uid != 0) {
373        syslog(LOG_ERR, "failed credential check: %m");
374        errmsg = "Permission Denied";
375        goto error_out;
376    }
377
378    /* Verify IP address */
379
380    if ((m_head = munge_parse(m_head, m_end)) == NULL)
381        goto error_out;
382    
383    if ((rv = check_munge_ip(m_head)) < 0)
384        goto error_out;
385
386    if (rv == 0) {
387        syslog(LOG_ERR, "%s: %s", "Munge IP address doesn't match", m_head);
388        errmsg = "Permission Denied";
389        goto error_out; 
390    }
391
392    /* Verify Port */
393
394    if ((m_head = munge_parse(m_head, m_end)) == NULL)
395        goto error_out;
396
397    errno = 0;
398    port = strtol(m_head, (char **)NULL, 10);
399    if (errno != 0) {
400        syslog(LOG_ERR, "%s: %s", "Bad port number from client", m_head);
401        errmsg = "Internal Error";
402        goto error_out;
403    }
404
405    if (port != args->port) {
406        syslog(LOG_ERR, "%s: %d, %d", "Port mismatch", args->port, port);
407        errmsg = "Protocol Error";
408        goto error_out;
409    }
410
411    /* Get Random Number */
412
413    if ((m_head = munge_parse(m_head, m_end)) == NULL)
414        goto error_out;
415
416    errno = 0;
417    randnum = strtol(m_head,(char **)NULL,10);
418    if (errno != 0) {
419        syslog(LOG_ERR, "%s: %d", "mqshd: Bad random number from client.", randnum);
420        errmsg = "Internal Error";
421        goto error_out;
422    }
423
424    if (args->port == 0 && randnum != 0) {
425        syslog(LOG_ERR,"protocol error, rand should be 0, %d", randnum);
426        errmsg = "Protocol Error";
427        goto error_out;
428    }
429
430    /* Get Command */
431
432    if ((m_head = munge_parse(m_head, m_end)) == NULL)
433        goto error_out;
434
435    if (strlen(m_head) < ARG_MAX) {
436        strncpy(&cmdbuf[0], m_head, sizeof(cmdbuf));
437        cmdbuf[sizeof(cmdbuf) - 1] = '\0';
438    } else {
439        syslog(LOG_ERR, "Not enough space for command: %s", m_head);
440        errmsg = "Command too long";
441        goto error_out;
442    }
443
444    free(mptr);
445    mptr = NULL;
446
447    if ((args->hostname = findhostname(fromp)) == NULL) {
448        errmsg = "Host Address Mismatch";
449        goto error_out;
450    }
451
452#ifdef USE_PAM
453    if (pamauth(args->pwd, "mqshell", args->pwd->pw_name, 
454                args->hostname, args->pwd->pw_name       ) < 0) {
455        syslog(LOG_ERR, "PAM failed authentication");
456        errmsg = pam_errmsg;
457        goto error_out;
458    }
459#endif
460
461error_out:
462
463    /* If desired, setup stderr connection */
464    args->sock = 0;
465    if (args->port != 0) {
466        char c;
467
468        if ((args->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
469            syslog(LOG_ERR,"create socket: %m");
470            goto bad;
471        }
472        sin.sin_family = AF_INET;
473        sin.sin_port = htons(args->port);
474        sin.sin_addr.s_addr = fromp->sin_addr.s_addr;
475        if (connect(args->sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
476            syslog(LOG_ERR,"%s: %m","connect second port: %m");
477            goto bad;
478        }
479
480        /* Sync with client to avoid race condition */
481        rv = read(0,&c,1);
482        if (rv != 1 || c != '\0') { 
483            syslog (LOG_ERR, "%s", "mqshd: Client not ready.");
484            goto bad;
485        }
486    }
487
488    if (errmsg != NULL) {
489        char buf[BUFSIZ], *bp = buf;
490        snprintf(bp, sizeof(buf)-1, "%c%s\n", '\01', errmsg);
491        fd_write_n(args->sock, buf, strlen(buf));
492        goto bad;
493    }
494
495    /* Write random number to stderr */
496    if (args->port != 0) {
497        randnum = htonl(randnum);
498        if ((rv = fd_write_n(args->sock, &randnum, sizeof(randnum))) == -1) {
499            syslog(LOG_ERR, "%s: %m", "write to stderr port: ");
500            error("Write error, %s\n", strerror(errno));
501            goto bad;
502        }
503    }
504
505    args->remuser = NULL;
506    args->locuser = NULL;
507    args->cmdbuf =  Strdup(cmdbuf);
508
509    return;
510
511bad:
512    free(mptr);
513    close(args->sock);
514    exit(1);
515}
516
517int main(int argc, char *argv[]) {
518    return qshell(argc, argv, &mqshell_get_args, "mqshd", 0);
519}
520
521/*
522 * vi: tabstop=4 shiftwidth=4 expandtab
523 */