Exemple #1
0
/* pgp passwd */
static int pgp_login(void *obj, struct passwd **uam_pwd,
		     char *ibuf, size_t ibuflen,
		     char *rbuf, size_t *rbuflen)
{
    size_t len, i;
    char *name;

    *rbuflen = 0;

    if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, (void *) &name, &i) < 0)
      return AFPERR_PARAM;

    len = (unsigned char) *ibuf++;
    if ( len > i ) {
	return( AFPERR_PARAM );
    }

    memcpy(name, ibuf, len );
    ibuf += len;
    name[ len ] = '\0';
    if ((unsigned long) ibuf & 1) /* padding */
      ++ibuf;

    if (( pgppwd = uam_getname(obj, name, i)) == NULL ) {
      return AFPERR_PARAM;
    }

    LOG(log_info, logtype_uams, "pgp login: %s", name);
    if (uam_checkuser(pgppwd) < 0)
      return AFPERR_NOTAUTH;

    /* get the challenge */
    len = (unsigned char) *ibuf++;
    /* challenge */
    
    /* get the signature. it's always 16 bytes. */
    if (uam_afpserver_option(obj, UAM_OPTION_SIGNATURE, 
			     (void *) &name, NULL) < 0) {
      *rbuflen = 0;
      goto pgp_fail;
    }
    memcpy(rbuf + KEYSIZE, name, KEYSIZE); 

pgp_fail:
    return AFPERR_PARAM;
}
Exemple #2
0
static int gss_logincont(void *obj,
                         struct passwd **uam_pwd,
                         char *ibuf, size_t ibuflen,
                         char *rbuf, size_t *rbuflen)
{
    struct passwd *pwd = NULL;
    uint16_t login_id;
    char *username;
    uint16_t ticket_len;
    char *p;
    int rblen;
    size_t userlen;
    struct session_info *sinfo;

    /* Apple's AFP 3.1 documentation specifies that this command
     * takes the following format:
     * pad (byte)
     * id returned in LoginExt response (uint16_t)
     * username (format unspecified)
     *   padded, when necessary, to end on an even boundary
     * ticket length (uint16_t)
     * ticket
     */

    /* Observation of AFP clients in the wild indicate that the actual
     * format of this request is as follows:
     * pad (byte) [consumed before login_ext is called]
     * ?? (byte) - always observed to be 0
     * id returned in LoginExt response (uint16_t)
     * username, encoding unspecified, null terminated C string,
     *   padded when the terminating null is an even numbered byte.
     *   The packet is formated such that the username begins on an
     *   odd numbered byte. Eg if the username is 3 characters and the
     *   terminating null makes 4, expect to pad the the result.
     *   The encoding of this string is unknown.
     * ticket length (uint16_t)
     * ticket
     */

    rblen = *rbuflen = 0;

    if (ibuflen < 1 +sizeof(login_id)) {
        LOG_LOGINCONT(log_info, "received incomplete packet");
        return AFPERR_PARAM;
    }
    ibuf++, ibuflen--; /* ?? */

    /* 2 byte ID from LoginExt -- always '00 01' in this implementation */
    memcpy(&login_id, ibuf, sizeof(login_id));
    ibuf += sizeof(login_id), ibuflen -= sizeof(login_id);
    login_id = ntohs(login_id);

    /* get the username buffer from apfd */
    if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &userlen) < 0)
        return AFPERR_MISC;

    /* get the session_info structure from afpd. We need the session key */
    if (uam_afpserver_option(obj, UAM_OPTION_SESSIONINFO, &sinfo, NULL) < 0)
        return AFPERR_MISC;

    if (sinfo->sessionkey == NULL || sinfo->sessionkey_len == 0) {
        /* Should never happen. Most likely way too old afpd version */
        LOG_LOGINCONT(log_error, "internal error: afpd's sessionkey not set");
        return AFPERR_MISC;
    }

    /* We skip past the 'username' parameter because all that matters is the ticket */
    p = ibuf;
    while ( *ibuf && ibuflen ) { ibuf++, ibuflen--; }
    if (ibuflen < 4) {
        LOG_LOGINCONT(log_info, "user is %s, no ticket", p);
        return AFPERR_PARAM;
    }

    ibuf++, ibuflen--; /* null termination */

    if ((ibuf - p + 1) % 2) ibuf++, ibuflen--; /* deal with potential padding */

    LOG_LOGINCONT(log_debug, "client thinks user is %s", p);

    /* get the length of the ticket the client sends us */
    memcpy(&ticket_len, ibuf, sizeof(ticket_len));
    ibuf += sizeof(ticket_len); ibuflen -= sizeof(ticket_len);
    ticket_len = ntohs(ticket_len);

    /* a little bounds checking */
    if (ticket_len > ibuflen) {
        LOG_LOGINCONT(log_info,
                      "invalid ticket length (%u > %u)",
                      ticket_len, ibuflen);
        return AFPERR_PARAM;
    }

    /* now try to authenticate */
    if (do_gss_auth(obj, ibuf, ticket_len, rbuf, &rblen, username, userlen, sinfo)) {
        LOG_LOGINCONT(log_info, "do_gss_auth() failed" );
        *rbuflen = 0;
        return AFPERR_MISC;
    }

    /* We use the username we got back from the gssapi client_name.
       Should we compare this to the username the client sent in the clear?
       We know the character encoding of the cleartext username (UTF8), what
       encoding is the gssapi name in? */
    if ((pwd = uam_getname( obj, username, userlen )) == NULL) {
        LOG_LOGINCONT(log_info, "uam_getname() failed for %s", username);
        return AFPERR_NOTAUTH;
    }
    if (uam_checkuser(pwd) < 0) {
        LOG_LOGINCONT(log_info, "`%s'' not a valid user", username);
        return AFPERR_NOTAUTH;
    }

    *rbuflen = rblen;
    *uam_pwd = pwd;
    return AFP_OK;
}
Exemple #3
0
/* get the principal from afpd and import it into server_name */
static int get_afpd_principal(void *obj, gss_name_t *server_name)
{
    OM_uint32 major_status = 0, minor_status = 0;
    char *fqdn, *service, *principal, *p;
    size_t fqdnlen=0, servicelen=0;
    size_t principal_length;
    gss_buffer_desc s_princ_buffer;

    /* get all the required information from afpd */
    if (uam_afpserver_option(obj, UAM_OPTION_FQDN, (void*) &fqdn, &fqdnlen) < 0)
        return 1;
    LOG(log_debug, logtype_uams, "get_afpd_principal: fqdn: %s", fqdn);

    if (uam_afpserver_option(obj, UAM_OPTION_KRB5SERVICE, (void *)&service, &servicelen) < 0)
        return 1;
    LOG(log_debug, logtype_uams, "get_afpd_principal: service: %s", service);

    /* we need all the info, log error and return if one's missing */
    if (!service || !servicelen || !fqdn || !fqdnlen) {
        LOG(log_error, logtype_uams,
            "get_afpd_principal: could not retrieve required information from afpd.");
        return 1;
    }

    /* allocate memory to hold the temporary principal string */
    principal_length = servicelen + 1 + fqdnlen + 1;
    if ( NULL == (principal = (char*) malloc( principal_length)) ) {
        LOG(log_error, logtype_uams,
            "get_afpd_principal: out of memory allocating %u bytes",
            principal_length);
        return 1;
    }

    /*
     * Build the principal string.
     * Format: 'service@fqdn'
     */
    strlcpy( principal, service, principal_length);
    strlcat( principal, "@", principal_length);

    /*
     * The fqdn we get from afpd may contain a port.
     * We need to strip the port from fqdn for principal.
     */
    if ((p = strchr(fqdn, ':')))
        *p = '\0';

    strlcat( principal, fqdn, principal_length);
    if (p)
        *p = ':';
    /*
     * Import our principal into the gssapi internal representation
     * stored in server_name.
     */
    s_princ_buffer.value = principal;
    s_princ_buffer.length = strlen( principal ) + 1;

    LOG(log_debug, logtype_uams, "get_afpd_principal: importing principal `%s'", principal);
    major_status = gss_import_name( &minor_status,
                                    &s_princ_buffer,
                                    GSS_C_NT_HOSTBASED_SERVICE,
                                    server_name );

    /*
     * Get rid of malloc'ed memmory.
     * Don't release the s_princ_buffer, we free principal instead.
     */
    free(principal);

    if (major_status != GSS_S_COMPLETE) {
        /* Importing our service principal failed, bail out. */
        log_status( "import_principal", major_status, minor_status );
        return 1;
    }
    return 0;
}